CameraHardwareInterface: Reconnect preview in HAL set_buffer_count
Workaround for b/27039775
Some camera device HAL v1 implementations expect that calling
preview_stream_ops->set_buffer_count resets the preview stream's flag
for whether any buffers have been queued up by the camera HAL, allowing
the HAL to dequeue all buffers in the stream again (instead of just its
own buffer count limit, which is lower).
The underlying buffer queue behavior has now changed, and that flag is
no longer reset on a change of buffer count, to support dynamic buffer
queue buffer count features.
To maintain backwards compatibility with HALv1 implementations that rely
on this implicit HAL interface behavior, add a disconnect/connect pair
to the set_buffer_count call, which will reset the dequeue flag, along
with all other preview stream parameters.
To maintain other parameters, cache them when they are originall
set (either by the HAL or by the higher-level camera client), and apply
them again after reconnecting.
Bug: 27039775
Change-Id: I9fa220b356715e7f8e48adc7acdffbfa598c329c
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 6aeab98..8ab9a65 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -295,9 +295,8 @@
// If preview has been already started, register preview buffers now.
if (mHardware->previewEnabled()) {
if (window != 0) {
- native_window_set_scaling_mode(window.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- native_window_set_buffers_transform(window.get(), mOrientation);
+ mHardware->setPreviewScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ mHardware->setPreviewTransform(mOrientation);
result = mHardware->setPreviewWindow(window);
}
}
@@ -404,10 +403,9 @@
}
if (mPreviewWindow != 0) {
- native_window_set_scaling_mode(mPreviewWindow.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- native_window_set_buffers_transform(mPreviewWindow.get(),
- mOrientation);
+ mHardware->setPreviewScalingMode(
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ mHardware->setPreviewTransform(mOrientation);
}
mHardware->setPreviewWindow(mPreviewWindow);
result = mHardware->startPreview();
@@ -641,8 +639,7 @@
if (mOrientation != orientation) {
mOrientation = orientation;
if (mPreviewWindow != 0) {
- native_window_set_buffers_transform(mPreviewWindow.get(),
- mOrientation);
+ mHardware->setPreviewTransform(mOrientation);
}
}
return OK;
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 7f14cd4..0fe76e5 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -73,10 +73,18 @@
class CameraHardwareInterface : public virtual RefBase {
public:
- CameraHardwareInterface(const char *name)
+ CameraHardwareInterface(const char *name):
+ mDevice(nullptr),
+ mName(name),
+ mPreviewScalingMode(NOT_SET),
+ mPreviewTransform(NOT_SET),
+ mPreviewWidth(NOT_SET),
+ mPreviewHeight(NOT_SET),
+ mPreviewFormat(NOT_SET),
+ mPreviewUsage(0),
+ mPreviewSwapInterval(NOT_SET),
+ mPreviewCrop{NOT_SET,NOT_SET,NOT_SET,NOT_SET}
{
- mDevice = 0;
- mName = name;
}
~CameraHardwareInterface()
@@ -118,9 +126,16 @@
status_t setPreviewWindow(const sp<ANativeWindow>& buf)
{
ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
-
if (mDevice->ops->set_preview_window) {
mPreviewWindow = buf;
+ if (buf != nullptr) {
+ if (mPreviewScalingMode != NOT_SET) {
+ setPreviewScalingMode(mPreviewScalingMode);
+ }
+ if (mPreviewTransform != NOT_SET) {
+ setPreviewTransform(mPreviewTransform);
+ }
+ }
mHalPreviewWindow.user = this;
ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,
&mHalPreviewWindow, mHalPreviewWindow.user);
@@ -130,6 +145,27 @@
return INVALID_OPERATION;
}
+ status_t setPreviewScalingMode(int scalingMode)
+ {
+ int rc = OK;
+ mPreviewScalingMode = scalingMode;
+ if (mPreviewWindow != nullptr) {
+ rc = native_window_set_scaling_mode(mPreviewWindow.get(),
+ scalingMode);
+ }
+ return rc;
+ }
+
+ status_t setPreviewTransform(int transform) {
+ int rc = OK;
+ mPreviewTransform = transform;
+ if (mPreviewWindow != nullptr) {
+ rc = native_window_set_buffers_transform(mPreviewWindow.get(),
+ mPreviewTransform);
+ }
+ return rc;
+ }
+
/** Set the notification and data callbacks */
void setCallbacks(notify_callback notify_cb,
data_callback data_cb,
@@ -569,6 +605,8 @@
return __this->mPreviewWindow.get();
}
#define anw(n) __to_anw(((struct camera_preview_window *)n)->user)
+#define hwi(n) reinterpret_cast<CameraHardwareInterface *>(\
+ ((struct camera_preview_window *)n)->user)
static int __dequeue_buffer(struct preview_stream_ops* w,
buffer_handle_t** buffer, int *stride)
@@ -617,6 +655,44 @@
static int __set_buffer_count(struct preview_stream_ops* w, int count)
{
ANativeWindow *a = anw(w);
+
+ if (a != nullptr) {
+ // Workaround for b/27039775
+ // Previously, setting the buffer count would reset the buffer
+ // queue's flag that allows for all buffers to be dequeued on the
+ // producer side, instead of just the producer's declared max count,
+ // if no filled buffers have yet been queued by the producer. This
+ // reset no longer happens, but some HALs depend on this behavior,
+ // so it needs to be maintained for HAL backwards compatibility.
+ // Simulate the prior behavior by disconnecting/reconnecting to the
+ // window and setting the values again. This has the drawback of
+ // actually causing memory reallocation, which may not have happened
+ // in the past.
+ CameraHardwareInterface *hw = hwi(w);
+ native_window_api_disconnect(a, NATIVE_WINDOW_API_CAMERA);
+ native_window_api_connect(a, NATIVE_WINDOW_API_CAMERA);
+ if (hw->mPreviewScalingMode != NOT_SET) {
+ native_window_set_scaling_mode(a, hw->mPreviewScalingMode);
+ }
+ if (hw->mPreviewTransform != NOT_SET) {
+ native_window_set_buffers_transform(a, hw->mPreviewTransform);
+ }
+ if (hw->mPreviewWidth != NOT_SET) {
+ native_window_set_buffers_dimensions(a,
+ hw->mPreviewWidth, hw->mPreviewHeight);
+ native_window_set_buffers_format(a, hw->mPreviewFormat);
+ }
+ if (hw->mPreviewUsage != 0) {
+ native_window_set_usage(a, hw->mPreviewUsage);
+ }
+ if (hw->mPreviewSwapInterval != NOT_SET) {
+ a->setSwapInterval(a, hw->mPreviewSwapInterval);
+ }
+ if (hw->mPreviewCrop.left != NOT_SET) {
+ native_window_set_crop(a, &(hw->mPreviewCrop));
+ }
+ }
+
return native_window_set_buffer_count(a, count);
}
@@ -625,7 +701,10 @@
{
int rc;
ANativeWindow *a = anw(w);
-
+ CameraHardwareInterface *hw = hwi(w);
+ hw->mPreviewWidth = width;
+ hw->mPreviewHeight = height;
+ hw->mPreviewFormat = format;
rc = native_window_set_buffers_dimensions(a, width, height);
if (!rc) {
rc = native_window_set_buffers_format(a, format);
@@ -637,12 +716,12 @@
int left, int top, int right, int bottom)
{
ANativeWindow *a = anw(w);
- android_native_rect_t crop;
- crop.left = left;
- crop.top = top;
- crop.right = right;
- crop.bottom = bottom;
- return native_window_set_crop(a, &crop);
+ CameraHardwareInterface *hw = hwi(w);
+ hw->mPreviewCrop.left = left;
+ hw->mPreviewCrop.top = top;
+ hw->mPreviewCrop.right = right;
+ hw->mPreviewCrop.bottom = bottom;
+ return native_window_set_crop(a, &(hw->mPreviewCrop));
}
static int __set_timestamp(struct preview_stream_ops *w,
@@ -654,12 +733,16 @@
static int __set_usage(struct preview_stream_ops* w, int usage)
{
ANativeWindow *a = anw(w);
+ CameraHardwareInterface *hw = hwi(w);
+ hw->mPreviewUsage = usage;
return native_window_set_usage(a, usage);
}
static int __set_swap_interval(struct preview_stream_ops *w, int interval)
{
ANativeWindow *a = anw(w);
+ CameraHardwareInterface *hw = hwi(w);
+ hw->mPreviewSwapInterval = interval;
return a->setSwapInterval(a, interval);
}
@@ -701,6 +784,17 @@
data_callback mDataCb;
data_callback_timestamp mDataCbTimestamp;
void *mCbUser;
+
+ // Cached values for preview stream parameters
+ static const int NOT_SET = -1;
+ int mPreviewScalingMode;
+ int mPreviewTransform;
+ int mPreviewWidth;
+ int mPreviewHeight;
+ int mPreviewFormat;
+ int mPreviewUsage;
+ int mPreviewSwapInterval;
+ android_native_rect_t mPreviewCrop;
};
}; // namespace android