Camera: Combine handling of deferred surface and shared surface

- Refactor the OutputConfiguration to contain isDeferred and isShared
  flag, and not contain NULL surface.
- Unify the handling of deferred surface and shared surface.

Test: Camera CTS, and manual testing of GoogleCamera use cases
Bug: 33777818
Change-Id: I5dd3472f0f2133699b0e9fbdd8ba456956222746
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index a55c23b..f6ca903 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -455,29 +455,15 @@
     const std::vector<sp<IGraphicBufferProducer>>& bufferProducers =
             outputConfiguration.getGraphicBufferProducers();
     size_t numBufferProducers = bufferProducers.size();
+    bool deferredConsumer = outputConfiguration.isDeferred();
+    bool isShared = outputConfiguration.isShared();
 
     if (numBufferProducers > MAX_SURFACES_PER_STREAM) {
         ALOGE("%s: GraphicBufferProducer count %zu for stream exceeds limit of %d",
               __FUNCTION__, bufferProducers.size(), MAX_SURFACES_PER_STREAM);
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Surface count is too high");
     }
-    if (numBufferProducers == 0) {
-        ALOGE("%s: GraphicBufferProducer count 0 is not valid", __FUNCTION__);
-        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Malformed surface");
-    }
-    size_t deferredConsumerCnt = 0;
-    for (auto bufferProducer : bufferProducers) {
-        if (bufferProducer == nullptr) {
-            deferredConsumerCnt++;
-        }
-    }
-    if (deferredConsumerCnt > MAX_DEFERRED_SURFACES) {
-        ALOGE("%s: %zu deferred consumer is not supported", __FUNCTION__, deferredConsumerCnt);
-        return STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                "More than %d deferred consumer", MAX_DEFERRED_SURFACES);
-    }
-    bool deferredConsumer = deferredConsumerCnt > 0;
-    bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 1;
+    bool deferredConsumerOnly = deferredConsumer && numBufferProducers == 0;
     int surfaceType = outputConfiguration.getSurfaceType();
     bool validSurfaceType = ((surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) ||
             (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE));
@@ -494,170 +480,51 @@
 
     std::vector<sp<Surface>> surfaces;
     std::vector<sp<IBinder>> binders;
-    int streamWidth, streamHeight, streamFormat;
-    int width, height, format;
-    int32_t streamConsumerUsage;
-    int32_t consumerUsage;
-    android_dataspace dataSpace, streamDataSpace;
     status_t err;
 
     // Create stream for deferred surface case.
     if (deferredConsumerOnly) {
-        return createDeferredSurfaceStreamLocked(outputConfiguration, newStreamId);
+        return createDeferredSurfaceStreamLocked(outputConfiguration, isShared, newStreamId);
     }
 
-    bool isFirstSurface = true;
-    streamWidth = -1;
-    streamHeight = -1;
-    streamFormat = -1;
-    streamDataSpace = HAL_DATASPACE_UNKNOWN;
-    streamConsumerUsage = 0;
-
+    OutputStreamInfo streamInfo;
+    bool isStreamInfoValid = false;
     for (auto& bufferProducer : bufferProducers) {
-        if (bufferProducer == nullptr) {
-            continue;
-        }
-
         // Don't create multiple streams for the same target surface
-        {
-            ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
-            if (index != NAME_NOT_FOUND) {
-                String8 msg = String8::format("Camera %s: Surface already has a stream created for it "
-                        "(ID %zd)", mCameraIdStr.string(), index);
-                ALOGW("%s: %s", __FUNCTION__, msg.string());
-                return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.string());
-            }
-        }
-
-        // HACK b/10949105
-        // Query consumer usage bits to set async operation mode for
-        // GLConsumer using controlledByApp parameter.
-        bool useAsync = false;
-        if ((err = bufferProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
-                &consumerUsage)) != OK) {
-            String8 msg = String8::format("Camera %s: Failed to query Surface consumer usage: %s (%d)",
-                    mCameraIdStr.string(), strerror(-err), err);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
-        }
-        if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
-            ALOGW("%s: Camera %s with consumer usage flag: 0x%x: Forcing asynchronous mode for stream",
-                    __FUNCTION__, mCameraIdStr.string(), consumerUsage);
-            useAsync = true;
-        }
-
-        int32_t disallowedFlags = GraphicBuffer::USAGE_HW_VIDEO_ENCODER |
-                                  GRALLOC_USAGE_RENDERSCRIPT;
-        int32_t allowedFlags = GraphicBuffer::USAGE_SW_READ_MASK |
-                               GraphicBuffer::USAGE_HW_TEXTURE |
-                               GraphicBuffer::USAGE_HW_COMPOSER;
-        bool flexibleConsumer = (consumerUsage & disallowedFlags) == 0 &&
-                (consumerUsage & allowedFlags) != 0;
-
         sp<IBinder> binder = IInterface::asBinder(bufferProducer);
-        sp<Surface> surface = new Surface(bufferProducer, useAsync);
-        ANativeWindow *anw = surface.get();
-
-        if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) {
-            String8 msg = String8::format("Camera %s: Failed to query Surface width: %s (%d)",
-                     mCameraIdStr.string(), strerror(-err), err);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
-        }
-        if ((err = anw->query(anw, NATIVE_WINDOW_HEIGHT, &height)) != OK) {
-            String8 msg = String8::format("Camera %s: Failed to query Surface height: %s (%d)",
-                    mCameraIdStr.string(), strerror(-err), err);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
-        }
-        if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
-            String8 msg = String8::format("Camera %s: Failed to query Surface format: %s (%d)",
-                    mCameraIdStr.string(), strerror(-err), err);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
-        }
-        if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE,
-                                reinterpret_cast<int*>(&dataSpace))) != OK) {
-            String8 msg = String8::format("Camera %s: Failed to query Surface dataspace: %s (%d)",
-                    mCameraIdStr.string(), strerror(-err), err);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+        ssize_t index = mStreamMap.indexOfKey(binder);
+        if (index != NAME_NOT_FOUND) {
+            String8 msg = String8::format("Camera %s: Surface already has a stream created for it "
+                    "(ID %zd)", mCameraIdStr.string(), index);
+            ALOGW("%s: %s", __FUNCTION__, msg.string());
+            return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.string());
         }
 
-        // FIXME: remove this override since the default format should be
-        //       IMPLEMENTATION_DEFINED. b/9487482
-        if (format >= HAL_PIXEL_FORMAT_RGBA_8888 &&
-            format <= HAL_PIXEL_FORMAT_BGRA_8888) {
-            ALOGW("%s: Camera %s: Overriding format %#x to IMPLEMENTATION_DEFINED",
-                  __FUNCTION__, mCameraIdStr.string(), format);
-            format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-        }
-        // Round dimensions to the nearest dimensions available for this format
-        if (flexibleConsumer && isPublicFormat(format) &&
-                !CameraDeviceClient::roundBufferDimensionNearest(width, height,
-                format, dataSpace, mDevice->info(), /*out*/&width, /*out*/&height)) {
-            String8 msg = String8::format("Camera %s: No supported stream configurations with "
-                    "format %#x defined, failed to create output stream",
-                    mCameraIdStr.string(), format);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-        }
-        if (isFirstSurface) {
-            streamWidth = width;
-            streamHeight = height;
-            streamFormat = format;
-            streamDataSpace = dataSpace;
-            streamConsumerUsage = consumerUsage;
-            isFirstSurface = false;
-        }
-        if (width != streamWidth) {
-            String8 msg = String8::format("Camera %s:Surface width doesn't match: %d vs %d",
-                     mCameraIdStr.string(), width, streamWidth);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-        }
-        if (height != streamHeight) {
-            String8 msg = String8::format("Camera %s:Surface height doesn't match: %d vs %d",
-                     mCameraIdStr.string(), height, streamHeight);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-        }
-        if (format != streamFormat) {
-            String8 msg = String8::format("Camera %s:Surface format doesn't match: %d vs %d",
-                     mCameraIdStr.string(), format, streamFormat);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-        }
-        if (dataSpace != streamDataSpace) {
-            String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d",
-                     mCameraIdStr.string(), dataSpace, streamDataSpace);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-        }
-        //At the native side, there isn't a way to check whether 2 surfaces come from the same
-        //surface class type. Use usage flag to approximate the comparison.
-        //TODO: Support surfaces of different surface class type.
-        if (consumerUsage != streamConsumerUsage) {
-            String8 msg = String8::format(
-                    "Camera %s:Surface usage flag doesn't match 0x%x vs 0x%x",
-                    mCameraIdStr.string(), consumerUsage, streamConsumerUsage);
-            ALOGE("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+        sp<Surface> surface;
+        res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer);
+
+        if (!res.isOk())
+            return res;
+
+        if (!isStreamInfoValid) {
+            isStreamInfoValid = true;
         }
 
-        binders.push_back(binder);
+        binders.push_back(IInterface::asBinder(bufferProducer));
         surfaces.push_back(surface);
     }
 
     int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
-    err = mDevice->createStream(surfaces, deferredConsumer, width, height, format, dataSpace,
+    err = mDevice->createStream(surfaces, deferredConsumer, streamInfo.width,
+            streamInfo.height, streamInfo.format, streamInfo.dataSpace,
             static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
-            &streamId, outputConfiguration.getSurfaceSetID());
+            &streamId, outputConfiguration.getSurfaceSetID(), isShared);
 
     if (err != OK) {
         res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
                 "Camera %s: Error creating output stream (%d x %d, fmt %x, dataSpace %x): %s (%d)",
-                mCameraIdStr.string(), width, height, format, dataSpace, strerror(-err), err);
+                mCameraIdStr.string(), streamInfo.width, streamInfo.height, streamInfo.format,
+                streamInfo.dataSpace, strerror(-err), err);
     } else {
         int i = 0;
         for (auto& binder : binders) {
@@ -665,9 +532,13 @@
                     __FUNCTION__, binder.get(), streamId, i);
             mStreamMap.add(binder, StreamSurfaceId(streamId, i++));
         }
+
+        mStreamInfoMap[streamId] = streamInfo;
+
         ALOGV("%s: Camera %s: Successfully created a new stream ID %d for output surface"
                     " (%d x %d) with format 0x%x.",
-                  __FUNCTION__, mCameraIdStr.string(), streamId, width, height, format);
+                  __FUNCTION__, mCameraIdStr.string(), streamId, streamInfo.width,
+                  streamInfo.height, streamInfo.format);
 
         // Set transform flags to ensure preview to be rotated correctly.
         res = setStreamTransformLocked(streamId);
@@ -680,6 +551,7 @@
 
 binder::Status CameraDeviceClient::createDeferredSurfaceStreamLocked(
         const hardware::camera2::params::OutputConfiguration &outputConfiguration,
+        bool isShared,
         /*out*/
         int* newStreamId) {
     int width, height, format, surfaceType;
@@ -708,7 +580,7 @@
     err = mDevice->createStream(noSurface, /*hasDeferredConsumer*/true, width,
             height, format, dataSpace,
             static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
-            &streamId, outputConfiguration.getSurfaceSetID(), consumerUsage);
+            &streamId, outputConfiguration.getSurfaceSetID(), isShared, consumerUsage);
 
     if (err != OK) {
         res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -720,6 +592,9 @@
         // relocated to mStreamMap.
         mDeferredStreams.push_back(streamId);
 
+        mStreamInfoMap.emplace(std::piecewise_construct, std::forward_as_tuple(streamId),
+                std::forward_as_tuple(width, height, format, dataSpace, consumerUsage));
+
         ALOGV("%s: Camera %s: Successfully created a new stream ID %d for a deferred surface"
                 " (%d x %d) stream with format 0x%x.",
               __FUNCTION__, mCameraIdStr.string(), streamId, width, height, format);
@@ -862,6 +737,140 @@
     }
 }
 
+binder::Status CameraDeviceClient::createSurfaceFromGbp(
+        OutputStreamInfo& streamInfo, bool isStreamInfoValid,
+        sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp) {
+
+    // bufferProducer must be non-null
+    if (gbp == nullptr) {
+        String8 msg = String8::format("Camera %s: Surface is NULL", mCameraIdStr.string());
+        ALOGW("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+    // HACK b/10949105
+    // Query consumer usage bits to set async operation mode for
+    // GLConsumer using controlledByApp parameter.
+    bool useAsync = false;
+    int32_t consumerUsage;
+    status_t err;
+    if ((err = gbp->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
+            &consumerUsage)) != OK) {
+        String8 msg = String8::format("Camera %s: Failed to query Surface consumer usage: %s (%d)",
+                mCameraIdStr.string(), strerror(-err), err);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+    }
+    if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
+        ALOGW("%s: Camera %s with consumer usage flag: 0x%x: Forcing asynchronous mode for stream",
+                __FUNCTION__, mCameraIdStr.string(), consumerUsage);
+        useAsync = true;
+    }
+
+    int32_t disallowedFlags = GraphicBuffer::USAGE_HW_VIDEO_ENCODER |
+                              GRALLOC_USAGE_RENDERSCRIPT;
+    int32_t allowedFlags = GraphicBuffer::USAGE_SW_READ_MASK |
+                           GraphicBuffer::USAGE_HW_TEXTURE |
+                           GraphicBuffer::USAGE_HW_COMPOSER;
+    bool flexibleConsumer = (consumerUsage & disallowedFlags) == 0 &&
+            (consumerUsage & allowedFlags) != 0;
+
+    surface = new Surface(gbp, useAsync);
+    ANativeWindow *anw = surface.get();
+
+    int width, height, format;
+    android_dataspace dataSpace;
+    if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) {
+        String8 msg = String8::format("Camera %s: Failed to query Surface width: %s (%d)",
+                 mCameraIdStr.string(), strerror(-err), err);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+    }
+    if ((err = anw->query(anw, NATIVE_WINDOW_HEIGHT, &height)) != OK) {
+        String8 msg = String8::format("Camera %s: Failed to query Surface height: %s (%d)",
+                mCameraIdStr.string(), strerror(-err), err);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+    }
+    if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
+        String8 msg = String8::format("Camera %s: Failed to query Surface format: %s (%d)",
+                mCameraIdStr.string(), strerror(-err), err);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+    }
+    if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE,
+            reinterpret_cast<int*>(&dataSpace))) != OK) {
+        String8 msg = String8::format("Camera %s: Failed to query Surface dataspace: %s (%d)",
+                mCameraIdStr.string(), strerror(-err), err);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+    }
+
+    // FIXME: remove this override since the default format should be
+    //       IMPLEMENTATION_DEFINED. b/9487482
+    if (format >= HAL_PIXEL_FORMAT_RGBA_8888 &&
+        format <= HAL_PIXEL_FORMAT_BGRA_8888) {
+        ALOGW("%s: Camera %s: Overriding format %#x to IMPLEMENTATION_DEFINED",
+                __FUNCTION__, mCameraIdStr.string(), format);
+        format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    }
+    // Round dimensions to the nearest dimensions available for this format
+    if (flexibleConsumer && isPublicFormat(format) &&
+            !CameraDeviceClient::roundBufferDimensionNearest(width, height,
+            format, dataSpace, mDevice->info(), /*out*/&width, /*out*/&height)) {
+        String8 msg = String8::format("Camera %s: No supported stream configurations with "
+                "format %#x defined, failed to create output stream",
+                mCameraIdStr.string(), format);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+
+    if (!isStreamInfoValid) {
+        streamInfo.width = width;
+        streamInfo.height = height;
+        streamInfo.format = format;
+        streamInfo.dataSpace = dataSpace;
+        streamInfo.consumerUsage = consumerUsage;
+        return binder::Status::ok();
+    }
+    if (width != streamInfo.width) {
+        String8 msg = String8::format("Camera %s:Surface width doesn't match: %d vs %d",
+                mCameraIdStr.string(), width, streamInfo.width);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+    if (height != streamInfo.height) {
+        String8 msg = String8::format("Camera %s:Surface height doesn't match: %d vs %d",
+                 mCameraIdStr.string(), height, streamInfo.height);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+    if (format != streamInfo.format) {
+        String8 msg = String8::format("Camera %s:Surface format doesn't match: %d vs %d",
+                 mCameraIdStr.string(), format, streamInfo.format);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+    if (dataSpace != streamInfo.dataSpace) {
+        String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d",
+                 mCameraIdStr.string(), dataSpace, streamInfo.dataSpace);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+    //At the native side, there isn't a way to check whether 2 surfaces come from the same
+    //surface class type. Use usage flag to approximate the comparison. Treat
+    //different preview surface usage flags as the same.
+    int32_t previewUsageMask =
+            GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_HW_COMPOSER;
+    if ((consumerUsage & ~previewUsageMask) != (streamInfo.consumerUsage & ~previewUsageMask)) {
+        String8 msg = String8::format(
+                "Camera %s:Surface usage flag doesn't match 0x%x vs 0x%x",
+                mCameraIdStr.string(), consumerUsage, streamInfo.consumerUsage);
+        ALOGE("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+    return binder::Status::ok();
+}
+
 bool CameraDeviceClient::roundBufferDimensionNearest(int32_t width, int32_t height,
         int32_t format, android_dataspace dataSpace, const CameraMetadata& info,
         /*out*/int32_t* outWidth, /*out*/int32_t* outHeight) {
@@ -1167,7 +1176,7 @@
     return res;
 }
 
-binder::Status CameraDeviceClient::setDeferredConfiguration(int32_t streamId,
+binder::Status CameraDeviceClient::finalizeOutputConfigurations(int32_t streamId,
         const hardware::camera2::params::OutputConfiguration &outputConfiguration) {
     ATRACE_CALL();
 
@@ -1179,70 +1188,84 @@
     const std::vector<sp<IGraphicBufferProducer> >& bufferProducers =
             outputConfiguration.getGraphicBufferProducers();
 
-    // Client code should guarantee that the surface is from SurfaceView or SurfaceTexture.
-    // And it's also saved in the last entry of graphicBufferProducer list
     if (bufferProducers.size() == 0) {
         ALOGE("%s: bufferProducers must not be empty", __FUNCTION__);
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
     }
 
-    // Right now, only first surface in the OutputConfiguration is allowed to be
-    // deferred. And all other surfaces are checked to be the same (not null) at
-    // the Java side.
-    sp<IGraphicBufferProducer> bufferProducer = bufferProducers[0];
-    if (bufferProducer == nullptr) {
-        ALOGE("%s: bufferProducer must not be null", __FUNCTION__);
-        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                "Target Surface is invalid");
+    // streamId should be in mStreamMap if this stream already has a surface attached
+    // to it. Otherwise, it should be in mDeferredStreams.
+    bool streamIdConfigured = false;
+    ssize_t deferredStreamIndex = NAME_NOT_FOUND;
+    for (size_t i = 0; i < mStreamMap.size(); i++) {
+        if (mStreamMap.valueAt(i).streamId() == streamId) {
+            streamIdConfigured = true;
+            break;
+        }
     }
-
-    // Check if this stream id is one of the deferred only streams
-    ssize_t index = NAME_NOT_FOUND;
-    if (bufferProducers.size() == 1) {
-        for (size_t i = 0; i < mDeferredStreams.size(); i++) {
-            if (streamId == mDeferredStreams[i]) {
-                index = i;
-                break;
-            }
+    for (size_t i = 0; i < mDeferredStreams.size(); i++) {
+        if (streamId == mDeferredStreams[i]) {
+            deferredStreamIndex = i;
+            break;
         }
 
-        if (index == NAME_NOT_FOUND) {
-            String8 msg = String8::format("Camera %s: deferred surface is set to a unknown stream"
-                    "(ID %d)", mCameraIdStr.string(), streamId);
-            ALOGW("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-        }
+    }
+    if (deferredStreamIndex == NAME_NOT_FOUND && !streamIdConfigured) {
+        String8 msg = String8::format("Camera %s: deferred surface is set to a unknown stream"
+                "(ID %d)", mCameraIdStr.string(), streamId);
+        ALOGW("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
     }
 
     if (!mDevice.get()) {
         return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
     }
 
-    // Don't create multiple streams for the same target surface
-    {
+    std::vector<sp<Surface>> consumerSurfaces;
+    std::vector<size_t> consumerSurfaceIds;
+    size_t surfaceId = 0;
+    for (auto& bufferProducer : bufferProducers) {
+        // Don't create multiple streams for the same target surface
         ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
         if (index != NAME_NOT_FOUND) {
-            String8 msg = String8::format("Camera %s: Surface already has a stream created "
+            ALOGV("Camera %s: Surface already has a stream created "
                     " for it (ID %zd)", mCameraIdStr.string(), index);
-            ALOGW("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.string());
+            surfaceId++;
+            continue;
         }
+
+        sp<Surface> surface;
+        res = createSurfaceFromGbp(mStreamInfoMap[streamId], true /*isStreamInfoValid*/,
+                surface, bufferProducer);
+
+        if (!res.isOk())
+            return res;
+
+        consumerSurfaces.push_back(surface);
+        consumerSurfaceIds.push_back(surfaceId);
+        surfaceId++;
     }
 
-    status_t err;
-
-    // Always set to async, as we know the deferred surface is for preview streaming.
-    sp<Surface> consumerSurface = new Surface(bufferProducer, /*useAsync*/true);
+    if (consumerSurfaces.size() == 0) {
+        String8 msg = String8::format("Camera %s: New OutputConfiguration has the same surfaces"
+                " for stream (ID %d)", mCameraIdStr.string(), streamId);
+        ALOGW("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
 
     // Finish the deferred stream configuration with the surface.
-    err = mDevice->setConsumerSurface(streamId, consumerSurface);
+    status_t err;
+    err = mDevice->setConsumerSurfaces(streamId, consumerSurfaces);
     if (err == OK) {
-        sp<IBinder> binder = IInterface::asBinder(bufferProducer);
-        ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %zu", __FUNCTION__,
-                binder.get(), streamId, bufferProducers.size()-1);
-        mStreamMap.add(binder, StreamSurfaceId(streamId, bufferProducers.size()-1));
-        if (index != NAME_NOT_FOUND) {
-            mDeferredStreams.removeItemsAt(index);
+        for (size_t i = 0; i < consumerSurfaces.size(); i++) {
+            sp<IBinder> binder = IInterface::asBinder(
+                    consumerSurfaces[i]->getIGraphicBufferProducer());
+            ALOGV("%s: mStreamMap add binder %p streamId %d, surfaceId %zu", __FUNCTION__,
+                    binder.get(), streamId, consumerSurfaceIds[i]);
+            mStreamMap.add(binder, StreamSurfaceId(streamId, consumerSurfaceIds[i]));
+        }
+        if (deferredStreamIndex != NAME_NOT_FOUND) {
+            mDeferredStreams.removeItemsAt(deferredStreamIndex);
         }
     } else if (err == NO_INIT) {
         res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 047ccf2..2f6d414 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -131,8 +131,8 @@
     // Prepare stream by preallocating up to maxCount of its buffers
     virtual binder::Status prepare2(int32_t maxCount, int32_t streamId);
 
-    // Set the deferred surface for a stream.
-    virtual binder::Status setDeferredConfiguration(int32_t streamId,
+    // Finalize the output configurations with surfaces not added before.
+    virtual binder::Status finalizeOutputConfigurations(int32_t streamId,
             const hardware::camera2::params::OutputConfiguration &outputConfiguration);
 
     /**
@@ -207,6 +207,23 @@
 
     }; // class StreamSurfaceId
 
+    // OutputStreamInfo describes the property of a camera stream.
+    class OutputStreamInfo {
+    public:
+        int width;
+        int height;
+        int format;
+        android_dataspace dataSpace;
+        int32_t consumerUsage;
+        OutputStreamInfo() :
+                width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
+                consumerUsage(0) {}
+        OutputStreamInfo(int _width, int _height, int _format, android_dataspace _dataSpace,
+                int32_t _consumerUsage) :
+                    width(_width), height(_height), format(_format),
+                    dataSpace(_dataSpace), consumerUsage(_consumerUsage) {}
+    };
+
 private:
     /** ICameraDeviceUser interface-related private members */
 
@@ -228,6 +245,7 @@
     // Create an output stream with surface deferred for future.
     binder::Status createDeferredSurfaceStreamLocked(
             const hardware::camera2::params::OutputConfiguration &outputConfiguration,
+            bool isShared,
             int* newStreamId = NULL);
 
     // Set the stream transform flags to automatically rotate the camera stream for preview use
@@ -244,6 +262,11 @@
     //check if format is not custom format
     static bool isPublicFormat(int32_t format);
 
+    // Create a Surface from an IGraphicBufferProducer. Returns error if
+    // IGraphicBufferProducer's property doesn't match with streamInfo
+    binder::Status createSurfaceFromGbp(OutputStreamInfo& streamInfo, bool isStreamInfoValid,
+            sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp);
+
     // IGraphicsBufferProducer binder -> Stream ID + Surface ID for output streams
     KeyedVector<sp<IBinder>, StreamSurfaceId> mStreamMap;
 
@@ -267,8 +290,10 @@
     // Surface is configured, the stream id will be moved to mStreamMap.
     Vector<int32_t> mDeferredStreams;
 
+    // stream ID -> outputStreamInfo mapping
+    std::unordered_map<int32_t, OutputStreamInfo> mStreamInfoMap;
+
     static const int32_t MAX_SURFACES_PER_STREAM = 2;
-    static const int32_t MAX_DEFERRED_SURFACES = 1;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index a873402..98a3fcc 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -121,7 +121,7 @@
             uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
             int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
-            uint32_t consumerUsage = 0) = 0;
+            bool isShared = false, uint32_t consumerUsage = 0) = 0;
 
     /**
      * Create an output stream of the requested size, format, rotation and
@@ -134,7 +134,7 @@
             bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
             int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
-            uint32_t consumerUsage = 0) = 0;
+            bool isShared = false, uint32_t consumerUsage = 0) = 0;
 
     /**
      * Create an input stream of width, height, and format.
@@ -341,7 +341,8 @@
     /**
      * Set the deferred consumer surface and finish the rest of the stream configuration.
      */
-    virtual status_t setConsumerSurface(int streamId, sp<Surface> consumer) = 0;
+    virtual status_t setConsumerSurfaces(int streamId,
+            const std::vector<sp<Surface>>& consumers) = 0;
 
 };
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 1675584..977e7a8 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1292,7 +1292,7 @@
 status_t Camera3Device::createStream(sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
-            int streamSetId, uint32_t consumerUsage) {
+            int streamSetId, bool isShared, uint32_t consumerUsage) {
     ATRACE_CALL();
 
     if (consumer == nullptr) {
@@ -1304,19 +1304,19 @@
     consumers.push_back(consumer);
 
     return createStream(consumers, /*hasDeferredConsumer*/ false, width, height,
-            format, dataSpace, rotation, id, streamSetId, consumerUsage);
+            format, dataSpace, rotation, id, streamSetId, isShared, consumerUsage);
 }
 
 status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers,
         bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
         android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
-        int streamSetId, uint32_t consumerUsage) {
+        int streamSetId, bool isShared, uint32_t consumerUsage) {
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
     ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
-            " consumer usage 0x%x", mId.string(), mNextStreamId, width, height, format, dataSpace, rotation,
-            consumerUsage);
+            " consumer usage 0x%x, isShared %d", mId.string(), mNextStreamId, width, height, format,
+            dataSpace, rotation, consumerUsage, isShared);
 
     status_t res;
     bool wasActive = false;
@@ -1370,8 +1370,6 @@
         return BAD_VALUE;
     }
 
-    bool streamSharing  = consumers.size() > 1 || (consumers.size()  > 0 && hasDeferredConsumer);
-
     // Use legacy dataspace values for older HALs
     if (mDeviceVersion <= CAMERA_DEVICE_API_VERSION_3_3) {
         dataSpace = mapToLegacyDataspace(dataSpace);
@@ -1403,14 +1401,14 @@
         newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                 width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
                 mTimestampOffset, streamSetId);
+    } else if (isShared) {
+        newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
+                width, height, format, consumerUsage, dataSpace, rotation,
+                mTimestampOffset, streamSetId);
     } else if (consumers.size() == 0 && hasDeferredConsumer) {
         newStream = new Camera3OutputStream(mNextStreamId,
                 width, height, format, consumerUsage, dataSpace, rotation,
                 mTimestampOffset, streamSetId);
-    } else if (streamSharing) {
-        newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
-                hasDeferredConsumer, width, height, format, consumerUsage,
-                dataSpace, rotation, mTimestampOffset, streamSetId);
     } else {
         newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                 width, height, format, dataSpace, rotation,
@@ -2067,14 +2065,16 @@
     }
 }
 
-status_t Camera3Device::setConsumerSurface(int streamId, sp<Surface> consumer) {
+status_t Camera3Device::setConsumerSurfaces(int streamId,
+        const std::vector<sp<Surface>>& consumers) {
     ATRACE_CALL();
-    ALOGV("%s: Camera %s: set consumer surface for stream %d", __FUNCTION__, mId.string(), streamId);
+    ALOGV("%s: Camera %s: set consumer surface for stream %d",
+            __FUNCTION__, mId.string(), streamId);
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
 
-    if (consumer == nullptr) {
-        CLOGE("Null consumer is passed!");
+    if (consumers.size() == 0) {
+        CLOGE("No consumer is passed!");
         return BAD_VALUE;
     }
 
@@ -2084,7 +2084,7 @@
         return idx;
     }
     sp<Camera3OutputStreamInterface> stream = mOutputStreams[idx];
-    status_t res = stream->setConsumer(consumer);
+    status_t res = stream->setConsumers(consumers);
     if (res != OK) {
         CLOGE("Stream %d set consumer failed (error %d %s) ", streamId, res, strerror(-res));
         return res;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 9b869a9..91d682e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -109,18 +109,18 @@
     // Actual stream creation/deletion is delayed until first request is submitted
     // If adding streams while actively capturing, will pause device before adding
     // stream, reconfiguring device, and unpausing. If the client create a stream
-    // with nullptr consumer surface, the client must then call setConsumer()
+    // with nullptr consumer surface, the client must then call setConsumers()
     // and finish the stream configuration before starting output streaming.
     status_t createStream(sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
             int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
-            uint32_t consumerUsage = 0) override;
+            bool isShared = false, uint32_t consumerUsage = 0) override;
     status_t createStream(const std::vector<sp<Surface>>& consumers,
             bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
             int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
-            uint32_t consumerUsage = 0) override;
+            bool isShared = false, uint32_t consumerUsage = 0) override;
 
     status_t createInputStream(
             uint32_t width, uint32_t height, int format,
@@ -183,10 +183,10 @@
     void             notifyStatus(bool idle); // updates from StatusTracker
 
     /**
-     * Set the deferred consumer surface to the output stream and finish the deferred
+     * Set the deferred consumer surfaces to the output stream and finish the deferred
      * consumer configuration.
      */
-    status_t setConsumerSurface(int streamId, sp<Surface> consumer) override;
+    status_t setConsumerSurfaces(int streamId, const std::vector<sp<Surface>>& consumers) override;
 
   private:
     static const size_t        kDumpLockAttempts  = 10;
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 7f61c7a..1a730d6 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -115,9 +115,9 @@
     return false;
 }
 
-status_t Camera3DummyStream::setConsumer(sp<Surface> consumer) {
-    ALOGE("%s: Stream %d: Dummy stream doesn't support set consumer surface %p!",
-            __FUNCTION__, mId, consumer.get());
+status_t Camera3DummyStream::setConsumers(const std::vector<sp<Surface>>& /*consumers*/) {
+    ALOGE("%s: Stream %d: Dummy stream doesn't support set consumer surface!",
+            __FUNCTION__, mId);
     return INVALID_OPERATION;
 }
 }; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 37efbbb..b6ec99c 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -70,9 +70,9 @@
     virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
 
     /**
-     * Set the consumer surface to the output stream.
+     * Set the consumer surfaces to the output stream.
      */
-    virtual status_t setConsumer(sp<Surface> consumer);
+    virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
 
   protected:
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 1e76a27..b5883e3 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -710,14 +710,19 @@
     Mutex::Autolock l(mLock);
 
     if (surface_id != 0) {
-        ALOGE("%s: surface_id for Camera3OutputStream should be 0!", __FUNCTION__);
+        ALOGE("%s: surface_id %zu for Camera3OutputStream should be 0!", __FUNCTION__, surface_id);
     }
     return mConsumer == nullptr;
 }
 
-status_t Camera3OutputStream::setConsumer(sp<Surface> consumer) {
-    if (consumer == nullptr) {
-        ALOGE("%s: it's illegal to set a null consumer surface!", __FUNCTION__);
+status_t Camera3OutputStream::setConsumers(const std::vector<sp<Surface>>& consumers) {
+    if (consumers.size() != 1) {
+        ALOGE("%s: it's illegal to set %zu consumer surfaces!",
+                  __FUNCTION__, consumers.size());
+        return INVALID_OPERATION;
+    }
+    if (consumers[0] == nullptr) {
+        ALOGE("%s: it's illegal to set null consumer surface!", __FUNCTION__);
         return INVALID_OPERATION;
     }
 
@@ -726,7 +731,7 @@
         return INVALID_OPERATION;
     }
 
-    mConsumer = consumer;
+    mConsumer = consumers[0];
     return OK;
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 26ea63f..080c721 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -138,9 +138,9 @@
     virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
 
     /**
-     * Set the consumer surface to the output stream.
+     * Set the consumer surfaces to the output stream.
      */
-    virtual status_t setConsumer(sp<Surface> consumer);
+    virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
 
     class BufferReleasedListener : public BnProducerListener {
         public:
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 6a911c6..11868e7 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -46,9 +46,9 @@
     virtual bool isConsumerConfigurationDeferred(size_t surface_id = 0) const = 0;
 
     /**
-     * Set the consumer surface to the output stream.
+     * Set the consumer surfaces to the output stream.
      */
-    virtual status_t setConsumer(sp<Surface> consumer) = 0;
+    virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers) = 0;
 
     /**
      * Detach an unused buffer from the stream.
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index b419e06..0d6a96c 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -22,7 +22,6 @@
 
 Camera3SharedOutputStream::Camera3SharedOutputStream(int id,
         const std::vector<sp<Surface>>& surfaces,
-        bool hasDeferredSurface,
         uint32_t width, uint32_t height, int format,
         uint32_t consumerUsage, android_dataspace dataSpace,
         camera3_stream_rotation_t rotation,
@@ -30,8 +29,7 @@
         Camera3OutputStream(id, CAMERA3_STREAM_OUTPUT, width, height,
                             format, dataSpace, rotation, consumerUsage,
                             timestampOffset, setId),
-        mSurfaces(surfaces),
-        mDeferred(hasDeferredSurface) {
+        mSurfaces(surfaces) {
 }
 
 Camera3SharedOutputStream::~Camera3SharedOutputStream() {
@@ -70,23 +68,35 @@
 
 bool Camera3SharedOutputStream::isConsumerConfigurationDeferred(size_t surface_id) const {
     Mutex::Autolock l(mLock);
-    return (mDeferred && surface_id >= mSurfaces.size());
+    return (surface_id >= mSurfaces.size());
 }
 
-status_t Camera3SharedOutputStream::setConsumer(sp<Surface> surface) {
-    if (surface == nullptr) {
-        ALOGE("%s: it's illegal to set a null consumer surface!", __FUNCTION__);
+status_t Camera3SharedOutputStream::setConsumers(const std::vector<sp<Surface>>& surfaces) {
+    if (surfaces.size() == 0) {
+        ALOGE("%s: it's illegal to set zero consumer surfaces!", __FUNCTION__);
         return INVALID_OPERATION;
     }
 
-    if (!mDeferred) {
-        ALOGE("%s: Current stream isn't deferred!", __FUNCTION__);
-        return INVALID_OPERATION;
+    status_t ret = OK;
+    for (auto& surface : surfaces) {
+        if (surface == nullptr) {
+            ALOGE("%s: it's illegal to set a null consumer surface!", __FUNCTION__);
+            return INVALID_OPERATION;
+        }
+
+        mSurfaces.push_back(surface);
+
+        // Only call addOutput if the splitter has been connected.
+        if (mStreamSplitter != nullptr) {
+            ret = mStreamSplitter->addOutput(surface, camera3_stream::max_buffers);
+            if (ret != OK) {
+                ALOGE("%s: addOutput failed with error code %d", __FUNCTION__, ret);
+                return ret;
+
+            }
+        }
     }
-
-    mSurfaces.push_back(surface);
-
-    return mStreamSplitter->addOutput(surface, camera3_stream::max_buffers);
+    return ret;
 }
 
 status_t Camera3SharedOutputStream::configureQueueLocked() {
@@ -124,7 +134,7 @@
 
 status_t Camera3SharedOutputStream::getEndpointUsage(uint32_t *usage) const {
 
-    status_t res;
+    status_t res = OK;
     uint32_t u = 0;
 
     if (mConsumer == nullptr) {
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 1b37d7c..cc96076 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -33,7 +33,7 @@
      * sharing between multiple streams.
      */
     Camera3SharedOutputStream(int id, const std::vector<sp<Surface>>& surfaces,
-            bool hasDeferredSurface, uint32_t width, uint32_t height, int format,
+            uint32_t width, uint32_t height, int format,
             uint32_t consumerUsage, android_dataspace dataSpace,
             camera3_stream_rotation_t rotation, nsecs_t timestampOffset,
             int setId = CAMERA3_STREAM_SET_ID_INVALID);
@@ -45,7 +45,7 @@
 
     virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
 
-    virtual status_t setConsumer(sp<Surface> consumer);
+    virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
 
 private:
     // Surfaces passed in constructor from app
@@ -68,8 +68,6 @@
 
     virtual status_t getEndpointUsage(uint32_t *usage) const;
 
-    bool mDeferred;
-
 }; // class Camera3SharedOutputStream
 
 } // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index b935141..07f9491 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -55,14 +55,15 @@
     // Add output surfaces. This has to be before creating internal buffer queue
     // in order to get max consumer side buffers.
     for (size_t i = 0; i < surfaces.size(); i++) {
-        if (surfaces[i] != nullptr) {
-            res = addOutputLocked(surfaces[i], hal_max_buffers,
-                    OutputType::NonDeferred);
-            if (res != OK) {
-                ALOGE("%s: Failed to add output surface: %s(%d)",
-                        __FUNCTION__, strerror(-res), res);
-                return res;
-            }
+        if (surfaces[i] == nullptr) {
+            ALOGE("%s: Fatal: surface is NULL", __FUNCTION__);
+            return BAD_VALUE;
+        }
+        res = addOutputLocked(surfaces[i], hal_max_buffers, OutputType::NonDeferred);
+        if (res != OK) {
+            ALOGE("%s: Failed to add output surface: %s(%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
         }
     }
 
@@ -110,7 +111,7 @@
 }
 
 status_t Camera3StreamSplitter::addOutput(
-        sp<Surface>& outputQueue, size_t hal_max_buffers) {
+        const sp<Surface>& outputQueue, size_t hal_max_buffers) {
     Mutex::Autolock lock(mMutex);
     return addOutputLocked(outputQueue, hal_max_buffers, OutputType::Deferred);
 }
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 5a25712..32ae073 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -61,7 +61,7 @@
     // outputQueue has not been added to the splitter. BAD_VALUE is returned if
     // outputQueue is NULL. See IGraphicBufferProducer::connect for explanations
     // of other error codes.
-    status_t addOutput(sp<Surface>& outputQueue, size_t hal_max_buffers);
+    status_t addOutput(const sp<Surface>& outputQueue, size_t hal_max_buffers);
 
     // Request surfaces for a particular frame number. The requested surfaces
     // are stored in a FIFO queue. And when the buffer becomes available from the