camera2: Add support for secondary surface for stream
- Enhance OutputConfiguration to contain multiple surfaces for one
underlying stream.
- Create Camera3SharedOutputStream to handle streams with multiple
surfaces.
- Create Camera3StreamSplitter to handle buffer flows between camera and
multiple consumers.
Test: cts, and manually test camera preview/snapshot/recording
Bug: 33777818
Change-Id: Ia010c3cc9d9b4bd5b9ea03cc42fe4e0a0d8033f1
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 12d0da8..1427e29 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -30,8 +30,9 @@
const int OutputConfiguration::INVALID_ROTATION = -1;
const int OutputConfiguration::INVALID_SET_ID = -1;
-sp<IGraphicBufferProducer> OutputConfiguration::getGraphicBufferProducer() const {
- return mGbp;
+const std::vector<sp<IGraphicBufferProducer>>&
+ OutputConfiguration::getGraphicBufferProducers() const {
+ return mGbps;
}
int OutputConfiguration::getRotation() const {
@@ -103,37 +104,60 @@
return err;
}
- view::Surface surfaceShim;
- if ((err = surfaceShim.readFromParcel(parcel)) != OK) {
- // Read surface failure for deferred surface configuration is expected.
- if (surfaceType == SURFACE_TYPE_SURFACE_VIEW ||
- surfaceType == SURFACE_TYPE_SURFACE_TEXTURE) {
- ALOGV("%s: Get null surface from a deferred surface configuration (%dx%d)",
- __FUNCTION__, width, height);
- err = OK;
- } else {
- ALOGE("%s: Failed to read surface from parcel", __FUNCTION__);
- return err;
- }
+ // numSurfaces is the total number of surfaces for this OutputConfiguration,
+ // regardless the surface is deferred or not.
+ int numSurfaces = 0;
+ if ((err = parcel->readInt32(&numSurfaces)) != OK) {
+ ALOGE("%s: Failed to read maxSurfaces from parcel", __FUNCTION__);
+ return err;
+ }
+ if (numSurfaces < 1) {
+ ALOGE("%s: there has to be at least 1 surface per"
+ " outputConfiguration", __FUNCTION__);
+ return BAD_VALUE;
}
- mGbp = surfaceShim.graphicBufferProducer;
+ // Read all surfaces from parcel. If a surface is deferred, readFromPacel
+ // returns error, and a null surface is put into the mGbps. We assume all
+ // deferred surfaces are after non-deferred surfaces in the parcel.
+ // TODO: Need better way to detect deferred surface than using error
+ // return from readFromParcel.
+ std::vector<sp<IGraphicBufferProducer>> gbps;
+ for (int i = 0; i < numSurfaces; i++) {
+ view::Surface surfaceShim;
+ if ((err = surfaceShim.readFromParcel(parcel)) != OK) {
+ // Read surface failure for deferred surface configuration is expected.
+ if ((surfaceType == SURFACE_TYPE_SURFACE_VIEW ||
+ surfaceType == SURFACE_TYPE_SURFACE_TEXTURE)) {
+ ALOGV("%s: Get null surface from a deferred surface configuration (%dx%d)",
+ __FUNCTION__, width, height);
+ err = OK;
+ } else {
+ ALOGE("%s: Failed to read surface from parcel", __FUNCTION__);
+ return err;
+ }
+ }
+ gbps.push_back(surfaceShim.graphicBufferProducer);
+ ALOGV("%s: OutputConfiguration: gbps[%d] : %p, name %s", __FUNCTION__,
+ i, gbps[i].get(), String8(surfaceShim.name).string());
+ }
+
mRotation = rotation;
mSurfaceSetID = setID;
mSurfaceType = surfaceType;
mWidth = width;
mHeight = height;
+ mGbps = std::move(gbps);
- ALOGV("%s: OutputConfiguration: bp = %p, name = %s, rotation = %d, setId = %d,"
- "surfaceType = %d", __FUNCTION__, mGbp.get(), String8(surfaceShim.name).string(),
- mRotation, mSurfaceSetID, mSurfaceType);
+ ALOGV("%s: OutputConfiguration: rotation = %d, setId = %d, surfaceType = %d",
+ __FUNCTION__, mRotation, mSurfaceSetID, mSurfaceType);
return err;
}
OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
int surfaceSetID) {
- mGbp = gbp;
+ mGbps.push_back(gbp);
mRotation = rotation;
mSurfaceSetID = surfaceSetID;
}
@@ -158,14 +182,53 @@
err = parcel->writeInt32(mHeight);
if (err != OK) return err;
- view::Surface surfaceShim;
- surfaceShim.name = String16("unknown_name"); // name of surface
- surfaceShim.graphicBufferProducer = mGbp;
-
- err = surfaceShim.writeToParcel(parcel);
+ int numSurfaces = mGbps.size();
+ err = parcel->writeInt32(numSurfaces);
if (err != OK) return err;
+ for (int i = 0; i < numSurfaces; i++) {
+ view::Surface surfaceShim;
+ surfaceShim.name = String16("unknown_name"); // name of surface
+ surfaceShim.graphicBufferProducer = mGbps[i];
+
+ err = surfaceShim.writeToParcel(parcel);
+ if (err != OK) return err;
+ }
+
return OK;
}
+bool OutputConfiguration::gbpsEqual(const OutputConfiguration& other) const {
+ const std::vector<sp<IGraphicBufferProducer> >& otherGbps =
+ other.getGraphicBufferProducers();
+
+ if (mGbps.size() != otherGbps.size()) {
+ return false;
+ }
+
+ for (size_t i = 0; i < mGbps.size(); i++) {
+ if (mGbps[i] != otherGbps[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool OutputConfiguration::gbpsLessThan(const OutputConfiguration& other) const {
+ const std::vector<sp<IGraphicBufferProducer> >& otherGbps =
+ other.getGraphicBufferProducers();
+
+ if (mGbps.size() != otherGbps.size()) {
+ return mGbps.size() < otherGbps.size();
+ }
+
+ for (size_t i = 0; i < mGbps.size(); i++) {
+ if (mGbps[i] != otherGbps[i]) {
+ return mGbps[i] < otherGbps[i];
+ }
+ }
+
+ return false;
+}
}; // namespace android