Merge "StagefrightRecorder: add VIDEO_ENCODER_VP8 case in setupVideoEncoder" into lmp-dev
diff --git a/camera/Android.mk b/camera/Android.mk
index bbdb47d..da5ac59 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -23,6 +23,7 @@
CameraMetadata.cpp \
CameraParameters.cpp \
CaptureResult.cpp \
+ CameraParameters2.cpp \
ICamera.cpp \
ICameraClient.cpp \
ICameraService.cpp \
diff --git a/camera/CameraParameters2.cpp b/camera/CameraParameters2.cpp
new file mode 100644
index 0000000..378afeb
--- /dev/null
+++ b/camera/CameraParameters2.cpp
@@ -0,0 +1,382 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+#define LOG_TAG "CameraParams2"
+// #define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <camera/CameraParameters2.h>
+
+namespace android {
+
+CameraParameters2::CameraParameters2()
+ : mMap()
+{
+}
+
+CameraParameters2::~CameraParameters2()
+{
+}
+
+String8 CameraParameters2::flatten() const
+{
+ String8 flattened("");
+ size_t size = mMap.size();
+
+ for (size_t i = 0; i < size; i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+
+ flattened += k;
+ flattened += "=";
+ flattened += v;
+ if (i != size-1)
+ flattened += ";";
+ }
+
+ ALOGV("%s: Flattened params = %s", __FUNCTION__, flattened.string());
+
+ return flattened;
+}
+
+void CameraParameters2::unflatten(const String8 ¶ms)
+{
+ const char *a = params.string();
+ const char *b;
+
+ mMap.clear();
+
+ for (;;) {
+ // Find the bounds of the key name.
+ b = strchr(a, '=');
+ if (b == 0)
+ break;
+
+ // Create the key string.
+ String8 k(a, (size_t)(b-a));
+
+ // Find the value.
+ a = b+1;
+ b = strchr(a, ';');
+ if (b == 0) {
+ // If there's no semicolon, this is the last item.
+ String8 v(a);
+ mMap.add(k, v);
+ break;
+ }
+
+ String8 v(a, (size_t)(b-a));
+ mMap.add(k, v);
+ a = b+1;
+ }
+}
+
+
+void CameraParameters2::set(const char *key, const char *value)
+{
+ // XXX i think i can do this with strspn()
+ if (strchr(key, '=') || strchr(key, ';')) {
+ //XXX ALOGE("Key \"%s\"contains invalid character (= or ;)", key);
+ return;
+ }
+
+ if (strchr(value, '=') || strchr(value, ';')) {
+ //XXX ALOGE("Value \"%s\"contains invalid character (= or ;)", value);
+ return;
+ }
+
+ // Replacing a value updates the key's order to be the new largest order
+ ssize_t res = mMap.replaceValueFor(String8(key), String8(value));
+ LOG_ALWAYS_FATAL_IF(res < 0, "replaceValueFor(%s,%s) failed", key, value);
+}
+
+void CameraParameters2::set(const char *key, int value)
+{
+ char str[16];
+ sprintf(str, "%d", value);
+ set(key, str);
+}
+
+void CameraParameters2::setFloat(const char *key, float value)
+{
+ char str[16]; // 14 should be enough. We overestimate to be safe.
+ snprintf(str, sizeof(str), "%g", value);
+ set(key, str);
+}
+
+const char *CameraParameters2::get(const char *key) const
+{
+ ssize_t idx = mMap.indexOfKey(String8(key));
+ if (idx < 0) {
+ return NULL;
+ } else {
+ return mMap.valueAt(idx).string();
+ }
+}
+
+int CameraParameters2::getInt(const char *key) const
+{
+ const char *v = get(key);
+ if (v == 0)
+ return -1;
+ return strtol(v, 0, 0);
+}
+
+float CameraParameters2::getFloat(const char *key) const
+{
+ const char *v = get(key);
+ if (v == 0) return -1;
+ return strtof(v, 0);
+}
+
+status_t CameraParameters2::compareSetOrder(const char *key1, const char *key2,
+ int *order) const {
+ if (key1 == NULL) {
+ ALOGE("%s: key1 must not be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ } else if (key2 == NULL) {
+ ALOGE("%s: key2 must not be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ } else if (order == NULL) {
+ ALOGE("%s: order must not be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ ssize_t index1 = mMap.indexOfKey(String8(key1));
+ ssize_t index2 = mMap.indexOfKey(String8(key2));
+ if (index1 < 0) {
+ ALOGW("%s: Key1 (%s) was not set", __FUNCTION__, key1);
+ return NAME_NOT_FOUND;
+ } else if (index2 < 0) {
+ ALOGW("%s: Key2 (%s) was not set", __FUNCTION__, key2);
+ return NAME_NOT_FOUND;
+ }
+
+ *order = (index1 == index2) ? 0 :
+ (index1 < index2) ? -1 :
+ 1;
+
+ return OK;
+}
+
+void CameraParameters2::remove(const char *key)
+{
+ mMap.removeItem(String8(key));
+}
+
+// Parse string like "640x480" or "10000,20000"
+static int parse_pair(const char *str, int *first, int *second, char delim,
+ char **endptr = NULL)
+{
+ // Find the first integer.
+ char *end;
+ int w = (int)strtol(str, &end, 10);
+ // If a delimeter does not immediately follow, give up.
+ if (*end != delim) {
+ ALOGE("Cannot find delimeter (%c) in str=%s", delim, str);
+ return -1;
+ }
+
+ // Find the second integer, immediately after the delimeter.
+ int h = (int)strtol(end+1, &end, 10);
+
+ *first = w;
+ *second = h;
+
+ if (endptr) {
+ *endptr = end;
+ }
+
+ return 0;
+}
+
+static void parseSizesList(const char *sizesStr, Vector<Size> &sizes)
+{
+ if (sizesStr == 0) {
+ return;
+ }
+
+ char *sizeStartPtr = (char *)sizesStr;
+
+ while (true) {
+ int width, height;
+ int success = parse_pair(sizeStartPtr, &width, &height, 'x',
+ &sizeStartPtr);
+ if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
+ ALOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
+ return;
+ }
+ sizes.push(Size(width, height));
+
+ if (*sizeStartPtr == '\0') {
+ return;
+ }
+ sizeStartPtr++;
+ }
+}
+
+void CameraParameters2::setPreviewSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(CameraParameters::KEY_PREVIEW_SIZE, str);
+}
+
+void CameraParameters2::getPreviewSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(CameraParameters::KEY_PREVIEW_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getPreferredPreviewSizeForVideo(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getSupportedPreviewSizes(Vector<Size> &sizes) const
+{
+ const char *previewSizesStr = get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
+ parseSizesList(previewSizesStr, sizes);
+}
+
+void CameraParameters2::setVideoSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(CameraParameters::KEY_VIDEO_SIZE, str);
+}
+
+void CameraParameters2::getVideoSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(CameraParameters::KEY_VIDEO_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getSupportedVideoSizes(Vector<Size> &sizes) const
+{
+ const char *videoSizesStr = get(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES);
+ parseSizesList(videoSizesStr, sizes);
+}
+
+void CameraParameters2::setPreviewFrameRate(int fps)
+{
+ set(CameraParameters::KEY_PREVIEW_FRAME_RATE, fps);
+}
+
+int CameraParameters2::getPreviewFrameRate() const
+{
+ return getInt(CameraParameters::KEY_PREVIEW_FRAME_RATE);
+}
+
+void CameraParameters2::getPreviewFpsRange(int *min_fps, int *max_fps) const
+{
+ *min_fps = *max_fps = -1;
+ const char *p = get(CameraParameters::KEY_PREVIEW_FPS_RANGE);
+ if (p == 0) return;
+ parse_pair(p, min_fps, max_fps, ',');
+}
+
+void CameraParameters2::setPreviewFpsRange(int min_fps, int max_fps)
+{
+ String8 str = String8::format("%d,%d", min_fps, max_fps);
+ set(CameraParameters::KEY_PREVIEW_FPS_RANGE, str.string());
+}
+
+void CameraParameters2::setPreviewFormat(const char *format)
+{
+ set(CameraParameters::KEY_PREVIEW_FORMAT, format);
+}
+
+const char *CameraParameters2::getPreviewFormat() const
+{
+ return get(CameraParameters::KEY_PREVIEW_FORMAT);
+}
+
+void CameraParameters2::setPictureSize(int width, int height)
+{
+ char str[32];
+ sprintf(str, "%dx%d", width, height);
+ set(CameraParameters::KEY_PICTURE_SIZE, str);
+}
+
+void CameraParameters2::getPictureSize(int *width, int *height) const
+{
+ *width = *height = -1;
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(CameraParameters::KEY_PICTURE_SIZE);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getSupportedPictureSizes(Vector<Size> &sizes) const
+{
+ const char *pictureSizesStr = get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
+ parseSizesList(pictureSizesStr, sizes);
+}
+
+void CameraParameters2::setPictureFormat(const char *format)
+{
+ set(CameraParameters::KEY_PICTURE_FORMAT, format);
+}
+
+const char *CameraParameters2::getPictureFormat() const
+{
+ return get(CameraParameters::KEY_PICTURE_FORMAT);
+}
+
+void CameraParameters2::dump() const
+{
+ ALOGD("dump: mMap.size = %d", mMap.size());
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ ALOGD("%s: %s\n", k.string(), v.string());
+ }
+}
+
+status_t CameraParameters2::dump(int fd, const Vector<String16>& args) const
+{
+ (void)args;
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ snprintf(buffer, 255, "CameraParameters2::dump: mMap.size = %zu\n", mMap.size());
+ result.append(buffer);
+ for (size_t i = 0; i < mMap.size(); i++) {
+ String8 k, v;
+ k = mMap.keyAt(i);
+ v = mMap.valueAt(i);
+ snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
+ result.append(buffer);
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/include/camera/CameraParameters2.h b/include/camera/CameraParameters2.h
new file mode 100644
index 0000000..88ad812
--- /dev/null
+++ b/include/camera/CameraParameters2.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014 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 ANDROID_HARDWARE_CAMERA_PARAMETERS2_H
+#define ANDROID_HARDWARE_CAMERA_PARAMETERS2_H
+
+#include <utils/Vector.h>
+#include <utils/String8.h>
+#include "CameraParameters.h"
+
+namespace android {
+
+/**
+ * A copy of CameraParameters plus ABI-breaking changes. Needed
+ * because some camera HALs directly link to CameraParameters and cannot
+ * tolerate an ABI change.
+ */
+class CameraParameters2
+{
+public:
+ CameraParameters2();
+ CameraParameters2(const String8 ¶ms) { unflatten(params); }
+ ~CameraParameters2();
+
+ String8 flatten() const;
+ void unflatten(const String8 ¶ms);
+
+ void set(const char *key, const char *value);
+ void set(const char *key, int value);
+ void setFloat(const char *key, float value);
+ // Look up string value by key.
+ // -- The string remains valid until the next set/remove of the same key,
+ // or until the map gets cleared.
+ const char *get(const char *key) const;
+ int getInt(const char *key) const;
+ float getFloat(const char *key) const;
+
+ // Compare the order that key1 was set vs the order that key2 was set.
+ //
+ // Sets the order parameter to an integer less than, equal to, or greater
+ // than zero if key1's set order was respectively, to be less than, to
+ // match, or to be greater than key2's set order.
+ //
+ // Error codes:
+ // * NAME_NOT_FOUND - if either key has not been set previously
+ // * BAD_VALUE - if any of the parameters are NULL
+ status_t compareSetOrder(const char *key1, const char *key2,
+ /*out*/
+ int *order) const;
+
+ void remove(const char *key);
+
+ void setPreviewSize(int width, int height);
+ void getPreviewSize(int *width, int *height) const;
+ void getSupportedPreviewSizes(Vector<Size> &sizes) const;
+
+ // Set the dimensions in pixels to the given width and height
+ // for video frames. The given width and height must be one
+ // of the supported dimensions returned from
+ // getSupportedVideoSizes(). Must not be called if
+ // getSupportedVideoSizes() returns an empty Vector of Size.
+ void setVideoSize(int width, int height);
+ // Retrieve the current dimensions (width and height)
+ // in pixels for video frames, which must be one of the
+ // supported dimensions returned from getSupportedVideoSizes().
+ // Must not be called if getSupportedVideoSizes() returns an
+ // empty Vector of Size.
+ void getVideoSize(int *width, int *height) const;
+ // Retrieve a Vector of supported dimensions (width and height)
+ // in pixels for video frames. If sizes returned from the method
+ // is empty, the camera does not support calls to setVideoSize()
+ // or getVideoSize(). In adddition, it also indicates that
+ // the camera only has a single output, and does not have
+ // separate output for video frames and preview frame.
+ void getSupportedVideoSizes(Vector<Size> &sizes) const;
+ // Retrieve the preferred preview size (width and height) in pixels
+ // for video recording. The given width and height must be one of
+ // supported preview sizes returned from getSupportedPreviewSizes().
+ // Must not be called if getSupportedVideoSizes() returns an empty
+ // Vector of Size. If getSupportedVideoSizes() returns an empty
+ // Vector of Size, the width and height returned from this method
+ // is invalid, and is "-1x-1".
+ void getPreferredPreviewSizeForVideo(int *width, int *height) const;
+
+ void setPreviewFrameRate(int fps);
+ int getPreviewFrameRate() const;
+ void getPreviewFpsRange(int *min_fps, int *max_fps) const;
+ void setPreviewFpsRange(int min_fps, int max_fps);
+ void setPreviewFormat(const char *format);
+ const char *getPreviewFormat() const;
+ void setPictureSize(int width, int height);
+ void getPictureSize(int *width, int *height) const;
+ void getSupportedPictureSizes(Vector<Size> &sizes) const;
+ void setPictureFormat(const char *format);
+ const char *getPictureFormat() const;
+
+ void dump() const;
+ status_t dump(int fd, const Vector<String16>& args) const;
+
+private:
+
+ // Quick and dirty map that maintains insertion order
+ template <typename KeyT, typename ValueT>
+ struct OrderedKeyedVector {
+
+ ssize_t add(const KeyT& key, const ValueT& value) {
+ return mList.add(Pair(key, value));
+ }
+
+ size_t size() const {
+ return mList.size();
+ }
+
+ const KeyT& keyAt(size_t idx) const {
+ return mList[idx].mKey;
+ }
+
+ const ValueT& valueAt(size_t idx) const {
+ return mList[idx].mValue;
+ }
+
+ const ValueT& valueFor(const KeyT& key) const {
+ ssize_t i = indexOfKey(key);
+ LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
+
+ return valueAt(i);
+ }
+
+ ssize_t indexOfKey(const KeyT& key) const {
+ size_t vectorIdx = 0;
+ for (; vectorIdx < mList.size(); ++vectorIdx) {
+ if (mList[vectorIdx].mKey == key) {
+ return (ssize_t) vectorIdx;
+ }
+ }
+
+ return NAME_NOT_FOUND;
+ }
+
+ ssize_t removeItem(const KeyT& key) {
+ size_t vectorIdx = (size_t) indexOfKey(key);
+
+ if (vectorIdx < 0) {
+ return vectorIdx;
+ }
+
+ return mList.removeAt(vectorIdx);
+ }
+
+ void clear() {
+ mList.clear();
+ }
+
+ // Same as removing and re-adding. The key's index changes to max.
+ ssize_t replaceValueFor(const KeyT& key, const ValueT& value) {
+ removeItem(key);
+ return add(key, value);
+ }
+
+ private:
+
+ struct Pair {
+ Pair() : mKey(), mValue() {}
+ Pair(const KeyT& key, const ValueT& value) :
+ mKey(key),
+ mValue(value) {}
+ KeyT mKey;
+ ValueT mValue;
+ };
+
+ Vector<Pair> mList;
+ };
+
+ /**
+ * Order matters: Keys that are set() later are stored later in the map.
+ *
+ * If two keys have meaning that conflict, then the later-set key
+ * wins.
+ *
+ * For example, preview FPS and preview FPS range conflict since only
+ * we only want to use the FPS range if that's the last thing that was set.
+ * So in that case, only use preview FPS range if it was set later than
+ * the preview FPS.
+ */
+ OrderedKeyedVector<String8,String8> mMap;
+};
+
+}; // namespace android
+
+#endif
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a706987..2c48306 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1898,7 +1898,8 @@
me, buffer->raw, buffer->size, me->mCallbackCookie,
CB_EVENT_FILL_BUFFER);
- if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
+ if ((me->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0 &&
+ actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
// We've reached EOS but the audio track is not stopped yet,
// keep playing silence.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 5e7ecfa..75e1371 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -148,6 +148,8 @@
mVideoIsAVC(false),
mOffloadAudio(false),
mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
+ mAudioDecoderGeneration(0),
+ mVideoDecoderGeneration(0),
mAudioEOS(false),
mVideoEOS(false),
mScanSourcesPending(false),
@@ -691,6 +693,25 @@
{
bool audio = msg->what() == kWhatAudioNotify;
+ int32_t currentDecoderGeneration =
+ (audio? mAudioDecoderGeneration : mVideoDecoderGeneration);
+ int32_t requesterGeneration = currentDecoderGeneration - 1;
+ CHECK(msg->findInt32("generation", &requesterGeneration));
+
+ if (requesterGeneration != currentDecoderGeneration) {
+ ALOGV("got message from old %s decoder, generation(%d:%d)",
+ audio ? "audio" : "video", requesterGeneration,
+ currentDecoderGeneration);
+ sp<AMessage> reply;
+ if (!(msg->findMessage("reply", &reply))) {
+ return;
+ }
+
+ reply->setInt32("err", INFO_DISCONTINUITY);
+ reply->post();
+ return;
+ }
+
int32_t what;
CHECK(msg->findInt32("what", &what));
@@ -943,11 +964,13 @@
}
void NuPlayer::finishFlushIfPossible() {
- if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) {
+ if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED
+ && mFlushingAudio != SHUT_DOWN) {
return;
}
- if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) {
+ if (mFlushingVideo != NONE && mFlushingVideo != FLUSHED
+ && mFlushingVideo != SHUT_DOWN) {
return;
}
@@ -958,11 +981,11 @@
mTimeDiscontinuityPending = false;
}
- if (mAudioDecoder != NULL) {
+ if (mAudioDecoder != NULL && mFlushingAudio == FLUSHED) {
mAudioDecoder->signalResume();
}
- if (mVideoDecoder != NULL) {
+ if (mVideoDecoder != NULL && mFlushingVideo == FLUSHED) {
mVideoDecoder->signalResume();
}
@@ -1061,6 +1084,7 @@
}
ALOGV("openAudioSink: try to open AudioSink in offload mode");
flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ flags &= ~AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
audioSinkChanged = true;
mAudioSink->close();
err = mAudioSink->open(
@@ -1150,17 +1174,21 @@
}
}
- sp<AMessage> notify =
- new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify,
- id());
-
if (audio) {
+ sp<AMessage> notify = new AMessage(kWhatAudioNotify, id());
+ ++mAudioDecoderGeneration;
+ notify->setInt32("generation", mAudioDecoderGeneration);
+
if (mOffloadAudio) {
*decoder = new DecoderPassThrough(notify);
} else {
*decoder = new Decoder(notify);
}
} else {
+ sp<AMessage> notify = new AMessage(kWhatVideoNotify, id());
+ ++mVideoDecoderGeneration;
+ notify->setInt32("generation", mVideoDecoderGeneration);
+
*decoder = new Decoder(notify, mNativeWindow);
}
(*decoder)->init();
@@ -1195,8 +1223,8 @@
sp<AMessage> reply;
CHECK(msg->findMessage("reply", &reply));
- if ((audio && IsFlushingState(mFlushingAudio))
- || (!audio && IsFlushingState(mFlushingVideo))) {
+ if ((audio && mFlushingAudio != NONE)
+ || (!audio && mFlushingVideo != NONE)) {
reply->setInt32("err", INFO_DISCONTINUITY);
reply->post();
return OK;
@@ -1276,15 +1304,6 @@
}
} else {
// This stream is unaffected by the discontinuity
-
- if (audio) {
- mFlushingAudio = FLUSHED;
- } else {
- mFlushingVideo = FLUSHED;
- }
-
- finishFlushIfPossible();
-
return -EWOULDBLOCK;
}
}
@@ -1335,7 +1354,8 @@
sp<AMessage> reply;
CHECK(msg->findMessage("reply", &reply));
- if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) {
+ if ((audio && mFlushingAudio != NONE)
+ || (!audio && mFlushingVideo != NONE)) {
// We're currently attempting to flush the decoder, in order
// to complete this, the decoder wants all its buffers back,
// so we don't want any output buffers it sent us (from before
@@ -1480,27 +1500,13 @@
needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
if (audio) {
- CHECK(mFlushingAudio == NONE
- || mFlushingAudio == AWAITING_DISCONTINUITY);
-
+ ALOGE_IF(mFlushingAudio != NONE,
+ "audio flushDecoder() is called in state %d", mFlushingAudio);
mFlushingAudio = newStatus;
-
- if (mFlushingVideo == NONE) {
- mFlushingVideo = (mVideoDecoder != NULL)
- ? AWAITING_DISCONTINUITY
- : FLUSHED;
- }
} else {
- CHECK(mFlushingVideo == NONE
- || mFlushingVideo == AWAITING_DISCONTINUITY);
-
+ ALOGE_IF(mFlushingVideo != NONE,
+ "video flushDecoder() is called in state %d", mFlushingVideo);
mFlushingVideo = newStatus;
-
- if (mFlushingAudio == NONE) {
- mFlushingAudio = (mAudioDecoder != NULL)
- ? AWAITING_DISCONTINUITY
- : FLUSHED;
- }
}
}
@@ -1590,18 +1596,6 @@
// an intermediate state, i.e. one more more decoders are currently
// flushing or shutting down.
- if (mRenderer != NULL) {
- // There's an edge case where the renderer owns all output
- // buffers and is paused, therefore the decoder will not read
- // more input data and will never encounter the matching
- // discontinuity. To avoid this, we resume the renderer.
-
- if (mFlushingAudio == AWAITING_DISCONTINUITY
- || mFlushingVideo == AWAITING_DISCONTINUITY) {
- mRenderer->resume();
- }
- }
-
if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
// We're currently flushing, postpone the reset until that's
// completed.
@@ -1666,14 +1660,6 @@
mTimeDiscontinuityPending = true;
- if (mFlushingAudio == NONE && (!audio || mAudioDecoder == NULL)) {
- mFlushingAudio = FLUSHED;
- }
-
- if (mFlushingVideo == NONE && (!video || mVideoDecoder == NULL)) {
- mFlushingVideo = FLUSHED;
- }
-
if (audio && mAudioDecoder != NULL) {
flushDecoder(true /* audio */, true /* needShutdown */);
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 48882c5..96306db 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -129,6 +129,8 @@
sp<CCDecoder> mCCDecoder;
sp<Renderer> mRenderer;
sp<ALooper> mRendererLooper;
+ int32_t mAudioDecoderGeneration;
+ int32_t mVideoDecoderGeneration;
List<sp<Action> > mDeferredActions;
@@ -143,7 +145,6 @@
enum FlushStatus {
NONE,
- AWAITING_DISCONTINUITY,
FLUSHING_DECODER,
FLUSHING_DECODER_SHUTDOWN,
SHUTTING_DOWN_DECODER,
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index bf7542f..140e1ae 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -167,6 +167,16 @@
mCondition.wait(mLock);
}
return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
+ case STATE_STOPPED:
+ // this is really just paused. handle as seek to start
+ mAtEOS = false;
+ mState = STATE_STOPPED_AND_PREPARING;
+ mIsAsyncPrepare = false;
+ mPlayer->seekToAsync(0);
+ while (mState == STATE_STOPPED_AND_PREPARING) {
+ mCondition.wait(mLock);
+ }
+ return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
default:
return INVALID_OPERATION;
};
@@ -181,6 +191,13 @@
mIsAsyncPrepare = true;
mPlayer->prepareAsync();
return OK;
+ case STATE_STOPPED:
+ // this is really just paused. handle as seek to start
+ mAtEOS = false;
+ mState = STATE_STOPPED_AND_PREPARING;
+ mIsAsyncPrepare = true;
+ mPlayer->seekToAsync(0);
+ return OK;
default:
return INVALID_OPERATION;
};
@@ -224,6 +241,7 @@
break;
case STATE_PAUSED:
+ case STATE_STOPPED_AND_PREPARED:
{
mPlayer->resume();
break;
@@ -239,7 +257,29 @@
}
status_t NuPlayerDriver::stop() {
- return pause();
+ Mutex::Autolock autoLock(mLock);
+
+ switch (mState) {
+ case STATE_RUNNING:
+ mPlayer->pause();
+ // fall through
+
+ case STATE_PAUSED:
+ notifyListener(MEDIA_STOPPED);
+ // fall through
+
+ case STATE_PREPARED:
+ case STATE_STOPPED:
+ case STATE_STOPPED_AND_PREPARING:
+ case STATE_STOPPED_AND_PREPARED:
+ mState = STATE_STOPPED;
+ break;
+
+ default:
+ return INVALID_OPERATION;
+ }
+
+ return OK;
}
status_t NuPlayerDriver::pause() {
@@ -348,7 +388,9 @@
break;
}
- notifyListener(MEDIA_STOPPED);
+ if (mState != STATE_STOPPED) {
+ notifyListener(MEDIA_STOPPED);
+ }
mState = STATE_RESET_IN_PROGRESS;
mPlayer->resetAsync();
@@ -483,7 +525,23 @@
}
void NuPlayerDriver::notifySeekComplete() {
- notifyListener(MEDIA_SEEK_COMPLETE);
+ bool wasSeeking = true;
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mState == STATE_STOPPED_AND_PREPARING) {
+ wasSeeking = false;
+ mState = STATE_STOPPED_AND_PREPARED;
+ mCondition.broadcast();
+ if (!mIsAsyncPrepare) {
+ // if we are preparing synchronously, no need to notify listener
+ return;
+ }
+ } else if (mState == STATE_STOPPED) {
+ // no need to notify listener
+ return;
+ }
+ }
+ notifyListener(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
}
void NuPlayerDriver::notifyFrameStats(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index a9ff8b6..f520395 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -86,6 +86,9 @@
STATE_RUNNING,
STATE_PAUSED,
STATE_RESET_IN_PROGRESS,
+ STATE_STOPPED, // equivalent to PAUSED
+ STATE_STOPPED_AND_PREPARING, // equivalent to PAUSED, but seeking
+ STATE_STOPPED_AND_PREPARED, // equivalent to PAUSED, but seek complete
};
mutable Mutex mLock;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 3640038..1213a18 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -93,10 +93,14 @@
{
Mutex::Autolock autoLock(mFlushLock);
if (audio) {
- CHECK(!mFlushingAudio);
+ if (mFlushingAudio) {
+ return;
+ }
mFlushingAudio = true;
} else {
- CHECK(!mFlushingVideo);
+ if (mFlushingVideo) {
+ return;
+ }
mFlushingVideo = true;
}
}
@@ -115,6 +119,14 @@
mSyncQueues = false;
}
+void NuPlayer::Renderer::signalAudioSinkChanged() {
+ (new AMessage(kWhatAudioSinkChanged, id()))->post();
+}
+
+void NuPlayer::Renderer::signalDisableOffloadAudio() {
+ (new AMessage(kWhatDisableOffloadAudio, id()))->post();
+}
+
void NuPlayer::Renderer::pause() {
(new AMessage(kWhatPause, id()))->post();
}
@@ -251,14 +263,6 @@
msg->post(delayUs);
}
-void NuPlayer::Renderer::signalAudioSinkChanged() {
- (new AMessage(kWhatAudioSinkChanged, id()))->post();
-}
-
-void NuPlayer::Renderer::signalDisableOffloadAudio() {
- (new AMessage(kWhatDisableOffloadAudio, id()))->post();
-}
-
void NuPlayer::Renderer::prepareForMediaRenderingStart() {
mAudioRenderingStartGeneration = mAudioQueueGeneration;
mVideoRenderingStartGeneration = mVideoQueueGeneration;
@@ -318,6 +322,7 @@
bool hasEOS = false;
size_t sizeCopied = 0;
+ bool firstEntry = true;
while (sizeCopied < size && !mAudioQueue.empty()) {
QueueEntry *entry = &*mAudioQueue.begin();
@@ -328,14 +333,14 @@
break;
}
- if (entry->mOffset == 0) {
+ if (firstEntry && entry->mOffset == 0) {
+ firstEntry = false;
int64_t mediaTimeUs;
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
if (mFirstAudioTimeUs == -1) {
mFirstAudioTimeUs = mediaTimeUs;
}
- mAnchorTimeMediaUs = mediaTimeUs;
uint32_t numFramesPlayed;
CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
@@ -716,6 +721,15 @@
int32_t audio;
CHECK(msg->findInt32("audio", &audio));
+ {
+ Mutex::Autolock autoLock(mFlushLock);
+ if (audio) {
+ mFlushingAudio = false;
+ } else {
+ mFlushingVideo = false;
+ }
+ }
+
// If we're currently syncing the queues, i.e. dropping audio while
// aligning the first audio/video buffer times and only one of the
// two queues has data, we may starve that queue by not requesting
@@ -734,17 +748,18 @@
{
Mutex::Autolock autoLock(mLock);
flushQueue(&mAudioQueue);
+
+ ++mAudioQueueGeneration;
+ prepareForMediaRenderingStart();
+
+ if (offloadingAudio()) {
+ mFirstAudioTimeUs = -1;
+ }
}
- Mutex::Autolock autoLock(mFlushLock);
- mFlushingAudio = false;
-
mDrainAudioQueuePending = false;
- ++mAudioQueueGeneration;
- prepareForMediaRenderingStart();
if (offloadingAudio()) {
- mFirstAudioTimeUs = -1;
mAudioSink->pause();
mAudioSink->flush();
mAudioSink->start();
@@ -752,9 +767,6 @@
} else {
flushQueue(&mVideoQueue);
- Mutex::Autolock autoLock(mFlushLock);
- mFlushingVideo = false;
-
mDrainVideoQueuePending = false;
++mVideoQueueGeneration;
@@ -852,13 +864,15 @@
void NuPlayer::Renderer::onPause() {
CHECK(!mPaused);
+ {
+ Mutex::Autolock autoLock(mLock);
+ ++mAudioQueueGeneration;
+ ++mVideoQueueGeneration;
+ prepareForMediaRenderingStart();
+ }
+
mDrainAudioQueuePending = false;
- ++mAudioQueueGeneration;
-
mDrainVideoQueuePending = false;
- ++mVideoQueueGeneration;
-
- prepareForMediaRenderingStart();
if (mHasAudio) {
mAudioSink->pause();
@@ -895,7 +909,12 @@
uint32_t numFramesPlayed;
CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
- int64_t currentPositionUs = mFirstAudioTimeUs
+ int64_t firstAudioTimeUs;
+ {
+ Mutex::Autolock autoLock(mLock);
+ firstAudioTimeUs = mFirstAudioTimeUs;
+ }
+ int64_t currentPositionUs = firstAudioTimeUs
+ (numFramesPlayed * mAudioSink->msecsPerFrame()) * 1000ll;
mAudioSink->stop();
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 3d1d40e..78758da 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2500,12 +2500,6 @@
data1, data2);
if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
- // There is no need to check whether mFilledBuffers is empty or not
- // when the OMX_EventPortSettingsChanged is not meant for reallocating
- // the output buffers.
- if (data1 == kPortIndexOutput) {
- CHECK(mFilledBuffers.empty());
- }
onPortSettingsChanged(data1);
} else if (data1 == kPortIndexOutput &&
(data2 == OMX_IndexConfigCommonOutputCrop ||
@@ -2899,7 +2893,7 @@
void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) {
CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex);
- CHECK_EQ((int)mState, (int)EXECUTING);
+ CHECK(mState == EXECUTING || mState == EXECUTING_TO_IDLE);
CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput);
CHECK(!mOutputPortSettingsChangedPending);
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 98b50dd..76f8f54 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -249,11 +249,15 @@
mPackets.push_back(buffer);
} else {
// hexdump(buffer->data(), buffer->size());
+ if (buffer->size() < 2) {
+ return MALFORMED_PACKET;
+ }
- CHECK_GE(buffer->size(), 2u);
unsigned AU_headers_length = U16_AT(buffer->data()); // in bits
- CHECK_GE(buffer->size(), 2 + (AU_headers_length + 7) / 8);
+ if (buffer->size() < 2 + (AU_headers_length + 7) / 8) {
+ return MALFORMED_PACKET;
+ }
List<AUHeader> headers;
@@ -342,7 +346,9 @@
it != headers.end(); ++it) {
const AUHeader &header = *it;
- CHECK_LE(offset + header.mSize, buffer->size());
+ if (buffer->size() < offset + header.mSize) {
+ return MALFORMED_PACKET;
+ }
sp<ABuffer> accessUnit = new ABuffer(header.mSize);
memcpy(accessUnit->data(), buffer->data() + offset, header.mSize);
@@ -352,8 +358,6 @@
CopyTimes(accessUnit, buffer);
mPackets.push_back(accessUnit);
}
-
- CHECK_EQ(offset, buffer->size());
}
queue->erase(queue->begin());
@@ -400,6 +404,7 @@
const sp<ARTPSource> &source) {
AssemblyStatus status = addPacket(source);
if (status == MALFORMED_PACKET) {
+ ALOGI("access unit is damaged");
mAccessUnitDamaged = true;
}
return status;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 193f8e4..f721d5c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -5017,9 +5017,12 @@
// activeTracks accumulates a copy of a subset of mActiveTracks
Vector< sp<RecordTrack> > activeTracks;
- // reference to the (first and only) fast track
+ // reference to the (first and only) active fast track
sp<RecordTrack> fastTrack;
+ // reference to a fast track which is about to be removed
+ sp<RecordTrack> fastTrackToRemove;
+
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -5058,6 +5061,10 @@
activeTrack = mActiveTracks[i];
if (activeTrack->isTerminated()) {
+ if (activeTrack->isFastTrack()) {
+ ALOG_ASSERT(fastTrackToRemove == 0);
+ fastTrackToRemove = activeTrack;
+ }
removeTrack_l(activeTrack);
mActiveTracks.remove(activeTrack);
mActiveTracksGen++;
@@ -5130,10 +5137,12 @@
effectChains[i]->process_l();
}
- // Start the fast capture if it's not already running
+ // Push a new fast capture state if fast capture is not already running, or cblk change
if (mFastCapture != 0) {
FastCaptureStateQueue *sq = mFastCapture->sq();
FastCaptureState *state = sq->begin();
+ bool didModify = false;
+ FastCaptureStateQueue::block_t block = FastCaptureStateQueue::BLOCK_UNTIL_PUSHED;
if (state->mCommand != FastCaptureState::READ_WRITE /* FIXME &&
(kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)*/) {
if (state->mCommand == FastCaptureState::COLD_IDLE) {
@@ -5147,19 +5156,32 @@
mFastCaptureDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
FastCaptureDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
#endif
- state->mCblk = fastTrack != 0 ? fastTrack->cblk() : NULL;
- sq->end();
- sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+ didModify = true;
+ }
+ audio_track_cblk_t *cblkOld = state->mCblk;
+ audio_track_cblk_t *cblkNew = fastTrack != 0 ? fastTrack->cblk() : NULL;
+ if (cblkNew != cblkOld) {
+ state->mCblk = cblkNew;
+ // block until acked if removing a fast track
+ if (cblkOld != NULL) {
+ block = FastCaptureStateQueue::BLOCK_UNTIL_ACKED;
+ }
+ didModify = true;
+ }
+ sq->end(didModify);
+ if (didModify) {
+ sq->push(block);
#if 0
if (kUseFastCapture == FastCapture_Dynamic) {
mNormalSource = mPipeSource;
}
#endif
- } else {
- sq->end(false /*didModify*/);
}
}
+ // now run the fast track destructor with thread mutex unlocked
+ fastTrackToRemove.clear();
+
// Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
// Only the client(s) that are too slow will overrun. But if even the fastest client is too
// slow, then this RecordThread will overrun by not calling HAL read often enough.
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 7766b90..fd5a426 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -487,12 +487,12 @@
}
if (client == NULL) {
needsNewClient = true;
- ret = connectHelperLocked(/*cameraClient*/NULL, // Empty binder callbacks
+ ret = connectHelperLocked(/*out*/client,
+ /*cameraClient*/NULL, // Empty binder callbacks
cameraId,
internalPackageName,
uid,
- pid,
- client);
+ pid);
if (ret != OK) {
// Error already logged by callee
@@ -659,14 +659,17 @@
return true;
}
-status_t CameraService::connectHelperLocked(const sp<ICameraClient>& cameraClient,
- int cameraId,
- const String16& clientPackageName,
- int clientUid,
- int callingPid,
- /*out*/
- sp<Client>& client,
- int halVersion) {
+status_t CameraService::connectHelperLocked(
+ /*out*/
+ sp<Client>& client,
+ /*in*/
+ const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ const String16& clientPackageName,
+ int clientUid,
+ int callingPid,
+ int halVersion,
+ bool legacyMode) {
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
@@ -678,7 +681,7 @@
case CAMERA_DEVICE_API_VERSION_1_0:
client = new CameraClient(this, cameraClient,
clientPackageName, cameraId,
- facing, callingPid, clientUid, getpid());
+ facing, callingPid, clientUid, getpid(), legacyMode);
break;
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
@@ -687,7 +690,7 @@
case CAMERA_DEVICE_API_VERSION_3_2:
client = new Camera2Client(this, cameraClient,
clientPackageName, cameraId,
- facing, callingPid, clientUid, getpid());
+ facing, callingPid, clientUid, getpid(), legacyMode);
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
@@ -704,7 +707,7 @@
// Only support higher HAL version device opened as HAL1.0 device.
client = new CameraClient(this, cameraClient,
clientPackageName, cameraId,
- facing, callingPid, clientUid, getpid());
+ facing, callingPid, clientUid, getpid(), legacyMode);
} else {
// Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
@@ -760,12 +763,12 @@
return OK;
}
- status = connectHelperLocked(cameraClient,
+ status = connectHelperLocked(/*out*/client,
+ cameraClient,
cameraId,
clientPackageName,
clientUid,
- callingPid,
- client);
+ callingPid);
if (status != OK) {
return status;
}
@@ -823,13 +826,14 @@
return OK;
}
- status = connectHelperLocked(cameraClient,
+ status = connectHelperLocked(/*out*/client,
+ cameraClient,
cameraId,
clientPackageName,
clientUid,
callingPid,
- client,
- halVersion);
+ halVersion,
+ /*legacyMode*/true);
if (status != OK) {
return status;
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index cb98c96..a7328cf 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -452,14 +452,17 @@
*
* Returns OK on success, or a negative error code.
*/
- status_t connectHelperLocked(const sp<ICameraClient>& cameraClient,
- int cameraId,
- const String16& clientPackageName,
- int clientUid,
- int callingPid,
- /*out*/
- sp<Client>& client,
- int halVersion = CAMERA_HAL_API_VERSION_UNSPECIFIED);
+ status_t connectHelperLocked(
+ /*out*/
+ sp<Client>& client,
+ /*in*/
+ const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ const String16& clientPackageName,
+ int clientUid,
+ int callingPid,
+ int halVersion = CAMERA_HAL_API_VERSION_UNSPECIFIED,
+ bool legacyMode = false);
};
} // namespace android
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 5eb5181..bc40971 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -53,7 +53,8 @@
int cameraFacing,
int clientPid,
uid_t clientUid,
- int servicePid):
+ int servicePid,
+ bool legacyMode):
Camera2ClientBase(cameraService, cameraClient, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
mParameters(cameraId, cameraFacing)
@@ -62,6 +63,8 @@
SharedParameters::Lock l(mParameters);
l.mParameters.state = Parameters::DISCONNECTED;
+
+ mLegacyMode = legacyMode;
}
status_t Camera2Client::initialize(camera_module_t *module)
@@ -1449,6 +1452,13 @@
return OK;
}
+ // the camera2 api legacy mode can unconditionally disable the shutter sound
+ if (mLegacyMode) {
+ ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
+ l.mParameters.playShutterSound = false;
+ return OK;
+ }
+
// Disabling shutter sound may not be allowed. In that case only
// allow the mediaserver process to disable the sound.
char value[PROPERTY_VALUE_MAX];
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 5ce757a..f5c3a30 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -89,7 +89,8 @@
int cameraFacing,
int clientPid,
uid_t clientUid,
- int servicePid);
+ int servicePid,
+ bool legacyMode);
virtual ~Camera2Client();
@@ -203,6 +204,7 @@
bool mAfInMotion;
/** Utility members */
+ bool mLegacyMode;
// Wait until the camera device has received the latest control settings
status_t syncWithDevice();
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index fb6b678..abe1235 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -38,7 +38,7 @@
const String16& clientPackageName,
int cameraId, int cameraFacing,
int clientPid, int clientUid,
- int servicePid):
+ int servicePid, bool legacyMode):
Client(cameraService, cameraClient, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid)
{
@@ -54,6 +54,7 @@
// Callback is disabled by default
mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
+ mLegacyMode = legacyMode;
mPlayShutterSound = true;
LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
}
@@ -576,6 +577,13 @@
return OK;
}
+ // the camera2 api legacy mode can unconditionally disable the shutter sound
+ if (mLegacyMode) {
+ ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
+ mPlayShutterSound = false;
+ return OK;
+ }
+
// Disabling shutter sound may not be allowed. In that case only
// allow the mediaserver process to disable the sound.
char value[PROPERTY_VALUE_MAX];
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 4b89564..6779f5e 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -64,7 +64,8 @@
int cameraFacing,
int clientPid,
int clientUid,
- int servicePid);
+ int servicePid,
+ bool legacyMode = false);
~CameraClient();
status_t initialize(camera_module_t *module);
@@ -129,6 +130,7 @@
int mPreviewCallbackFlag;
int mOrientation; // Current display orientation
bool mPlayShutterSound;
+ bool mLegacyMode; // camera2 api legacy mode?
// Ensures atomicity among the public methods
mutable Mutex mLock;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 30a6c7b..e7f9a78 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "Camera2-Parameters"
#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -115,26 +115,6 @@
staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
if (!availableFpsRanges.count) return NO_INIT;
- previewFpsRange[0] = availableFpsRanges.data.i32[0];
- previewFpsRange[1] = availableFpsRanges.data.i32[1];
-
- params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
- String8::format("%d,%d",
- previewFpsRange[0] * kFpsToApiScale,
- previewFpsRange[1] * kFpsToApiScale));
-
- {
- String8 supportedPreviewFpsRange;
- for (size_t i=0; i < availableFpsRanges.count; i += 2) {
- if (i != 0) supportedPreviewFpsRange += ",";
- supportedPreviewFpsRange += String8::format("(%d,%d)",
- availableFpsRanges.data.i32[i] * kFpsToApiScale,
- availableFpsRanges.data.i32[i+1] * kFpsToApiScale);
- }
- params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
- supportedPreviewFpsRange);
- }
-
previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
params.set(CameraParameters::KEY_PREVIEW_FORMAT,
formatEnumToString(previewFormat)); // NV21
@@ -200,6 +180,9 @@
supportedPreviewFormats);
}
+ previewFpsRange[0] = availableFpsRanges.data.i32[0];
+ previewFpsRange[1] = availableFpsRanges.data.i32[1];
+
// PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but
// still have to do something sane for them
@@ -208,6 +191,27 @@
params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
previewFps);
+ // PREVIEW_FPS_RANGE
+ // -- Order matters. Set range after single value to so that a roundtrip
+ // of setParameters(getParameters()) would keep the FPS range in higher
+ // order.
+ params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
+ String8::format("%d,%d",
+ previewFpsRange[0] * kFpsToApiScale,
+ previewFpsRange[1] * kFpsToApiScale));
+
+ {
+ String8 supportedPreviewFpsRange;
+ for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ if (i != 0) supportedPreviewFpsRange += ",";
+ supportedPreviewFpsRange += String8::format("(%d,%d)",
+ availableFpsRanges.data.i32[i] * kFpsToApiScale,
+ availableFpsRanges.data.i32[i+1] * kFpsToApiScale);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
+ supportedPreviewFpsRange);
+ }
+
{
SortedVector<int32_t> sortedPreviewFrameRates;
@@ -640,8 +644,17 @@
focusMode = Parameters::FOCUS_MODE_AUTO;
params.set(CameraParameters::KEY_FOCUS_MODE,
CameraParameters::FOCUS_MODE_AUTO);
- String8 supportedFocusModes(CameraParameters::FOCUS_MODE_INFINITY);
- bool addComma = true;
+ String8 supportedFocusModes;
+ bool addComma = false;
+ camera_metadata_ro_entry_t focusDistanceCalibration =
+ staticInfo(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, 0, 0, false);
+
+ if (focusDistanceCalibration.count &&
+ focusDistanceCalibration.data.u8[0] !=
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED) {
+ supportedFocusModes += CameraParameters::FOCUS_MODE_INFINITY;
+ addComma = true;
+ }
for (size_t i=0; i < availableAfModes.count; i++) {
if (addComma) supportedFocusModes += ",";
@@ -1103,7 +1116,7 @@
status_t Parameters::set(const String8& paramString) {
status_t res;
- CameraParameters newParams(paramString);
+ CameraParameters2 newParams(paramString);
// TODO: Currently ignoring any changes to supposedly read-only parameters
// such as supported preview sizes, etc. Should probably produce an error if
@@ -1146,29 +1159,73 @@
// RECORDING_HINT (always supported)
validatedParams.recordingHint = boolFromString(
newParams.get(CameraParameters::KEY_RECORDING_HINT) );
- bool recordingHintChanged = validatedParams.recordingHint != recordingHint;
- ALOGV_IF(recordingHintChanged, "%s: Recording hint changed to %d",
- __FUNCTION__, recordingHintChanged);
+ IF_ALOGV() { // Avoid unused variable warning
+ bool recordingHintChanged =
+ validatedParams.recordingHint != recordingHint;
+ if (recordingHintChanged) {
+ ALOGV("%s: Recording hint changed to %d",
+ __FUNCTION__, validatedParams.recordingHint);
+ }
+ }
// PREVIEW_FPS_RANGE
- bool fpsRangeChanged = false;
- int32_t lastSetFpsRange[2];
- params.getPreviewFpsRange(&lastSetFpsRange[0], &lastSetFpsRange[1]);
- lastSetFpsRange[0] /= kFpsToApiScale;
- lastSetFpsRange[1] /= kFpsToApiScale;
+ /**
+ * Use the single FPS value if it was set later than the range.
+ * Otherwise, use the range value.
+ */
+ bool fpsUseSingleValue;
+ {
+ const char *fpsRange, *fpsSingle;
+ fpsRange = newParams.get(CameraParameters::KEY_PREVIEW_FRAME_RATE);
+ fpsSingle = newParams.get(CameraParameters::KEY_PREVIEW_FPS_RANGE);
+
+ /**
+ * Pick either the range or the single key if only one was set.
+ *
+ * If both are set, pick the one that has greater set order.
+ */
+ if (fpsRange == NULL && fpsSingle == NULL) {
+ ALOGE("%s: FPS was not set. One of %s or %s must be set.",
+ __FUNCTION__, CameraParameters::KEY_PREVIEW_FRAME_RATE,
+ CameraParameters::KEY_PREVIEW_FPS_RANGE);
+ return BAD_VALUE;
+ } else if (fpsRange == NULL) {
+ fpsUseSingleValue = true;
+ ALOGV("%s: FPS range not set, using FPS single value",
+ __FUNCTION__);
+ } else if (fpsSingle == NULL) {
+ fpsUseSingleValue = false;
+ ALOGV("%s: FPS single not set, using FPS range value",
+ __FUNCTION__);
+ } else {
+ int fpsKeyOrder;
+ res = newParams.compareSetOrder(
+ CameraParameters::KEY_PREVIEW_FRAME_RATE,
+ CameraParameters::KEY_PREVIEW_FPS_RANGE,
+ &fpsKeyOrder);
+ LOG_ALWAYS_FATAL_IF(res != OK, "Impossibly bad FPS keys");
+
+ fpsUseSingleValue = (fpsKeyOrder > 0);
+
+ }
+
+ ALOGV("%s: Preview FPS value is used from '%s'",
+ __FUNCTION__, fpsUseSingleValue ? "single" : "range");
+ }
newParams.getPreviewFpsRange(&validatedParams.previewFpsRange[0],
&validatedParams.previewFpsRange[1]);
+
validatedParams.previewFpsRange[0] /= kFpsToApiScale;
validatedParams.previewFpsRange[1] /= kFpsToApiScale;
- // Compare the FPS range value from the last set() to the current set()
- // to determine if the client has changed it
- if (validatedParams.previewFpsRange[0] != lastSetFpsRange[0] ||
- validatedParams.previewFpsRange[1] != lastSetFpsRange[1]) {
+ // Ignore the FPS range if the FPS single has higher precedence
+ if (!fpsUseSingleValue) {
+ ALOGV("%s: Preview FPS range (%d, %d)", __FUNCTION__,
+ validatedParams.previewFpsRange[0],
+ validatedParams.previewFpsRange[1]);
- fpsRangeChanged = true;
camera_metadata_ro_entry_t availablePreviewFpsRanges =
staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
for (i = 0; i < availablePreviewFpsRanges.count; i += 2) {
@@ -1217,14 +1274,13 @@
}
}
- // PREVIEW_FRAME_RATE Deprecated, only use if the preview fps range is
- // unchanged this time. The single-value FPS is the same as the minimum of
- // the range. To detect whether the application has changed the value of
- // previewFps, compare against their last-set preview FPS.
- if (!fpsRangeChanged) {
+ // PREVIEW_FRAME_RATE Deprecated
+ // - Use only if the single FPS value was set later than the FPS range
+ if (fpsUseSingleValue) {
int previewFps = newParams.getPreviewFrameRate();
- int lastSetPreviewFps = params.getPreviewFrameRate();
- if (previewFps != lastSetPreviewFps || recordingHintChanged) {
+ ALOGV("%s: Preview FPS single value requested: %d",
+ __FUNCTION__, previewFps);
+ {
camera_metadata_ro_entry_t availableFrameRates =
staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
/**
@@ -1293,6 +1349,35 @@
}
}
+ /**
+ * Update Preview FPS and Preview FPS ranges based on
+ * what we actually set.
+ *
+ * This updates the API-visible (Camera.Parameters#getParameters) values of
+ * the FPS fields, not only the internal versions.
+ *
+ * Order matters: The value that was set last takes precedence.
+ * - If the client does a setParameters(getParameters()) we retain
+ * the same order for preview FPS.
+ */
+ if (!fpsUseSingleValue) {
+ // Set fps single, then fps range (range wins)
+ newParams.setPreviewFrameRate(
+ fpsFromRange(/*min*/validatedParams.previewFpsRange[0],
+ /*max*/validatedParams.previewFpsRange[1]));
+ newParams.setPreviewFpsRange(
+ validatedParams.previewFpsRange[0] * kFpsToApiScale,
+ validatedParams.previewFpsRange[1] * kFpsToApiScale);
+ } else {
+ // Set fps range, then fps single (single wins)
+ newParams.setPreviewFpsRange(
+ validatedParams.previewFpsRange[0] * kFpsToApiScale,
+ validatedParams.previewFpsRange[1] * kFpsToApiScale);
+ // Set this to the same value, but with higher priority
+ newParams.setPreviewFrameRate(
+ newParams.getPreviewFrameRate());
+ }
+
// PICTURE_SIZE
newParams.getPictureSize(&validatedParams.pictureWidth,
&validatedParams.pictureHeight);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index f95c69a..d9d33c4 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -25,6 +25,7 @@
#include <utils/Vector.h>
#include <utils/KeyedVector.h>
#include <camera/CameraParameters.h>
+#include <camera/CameraParameters2.h>
#include <camera/CameraMetadata.h>
namespace android {
@@ -32,7 +33,7 @@
/**
* Current camera state; this is the full state of the Camera under the old
- * camera API (contents of the CameraParameters object in a more-efficient
+ * camera API (contents of the CameraParameters2 object in a more-efficient
* format, plus other state). The enum values are mostly based off the
* corresponding camera2 enums, not the camera1 strings. A few are defined here
* if they don't cleanly map to camera2 values.
@@ -136,7 +137,7 @@
LIGHTFX_HDR
} lightFx;
- CameraParameters params;
+ CameraParameters2 params;
String8 paramsFlattened;
// These parameters are also part of the camera API-visible state, but not
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index d7b1871..3f6254f 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -381,18 +381,7 @@
if (hal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_2) {
ALOGV("%s: register_stream_buffers unused as of HAL3.2", __FUNCTION__);
- /**
- * Skip the NULL check if camera.dev.register_stream is 1.
- *
- * For development-validation purposes only.
- *
- * TODO: Remove the property check before shipping L (b/13914251).
- */
- char value[PROPERTY_VALUE_MAX] = { '\0', };
- property_get("camera.dev.register_stream", value, "0");
- int propInt = atoi(value);
-
- if (propInt == 0 && hal3Device->ops->register_stream_buffers != NULL) {
+ if (hal3Device->ops->register_stream_buffers != NULL) {
ALOGE("%s: register_stream_buffers is deprecated in HAL3.2; "
"must be set to NULL in camera3_device::ops", __FUNCTION__);
return INVALID_OPERATION;