Configure streams.

Set up the camera HAL according to the request streams.
Upgrades this flow from the 3.0 to 3.4 version, where
streams are not registered with buffers, and have a few
additional fields.

BUG: http://b/29921457, http://b/29221641
Change-Id: I36f67da374e6919caad6f202f31b72b0de2bb3bf
diff --git a/modules/camera/3_4/Camera.cpp b/modules/camera/3_4/Camera.cpp
index bbcdf7e..d1d1a9e 100644
--- a/modules/camera/3_4/Camera.cpp
+++ b/modules/camera/3_4/Camera.cpp
@@ -152,6 +152,7 @@
 {
     camera3_stream_t *astream;
     Stream **newStreams = NULL;
+    int res = 0;
 
     ALOGV("%s:%d: stream_config=%p", __func__, mId, stream_config);
     ATRACE_CALL();
@@ -193,13 +194,19 @@
     }
 
     // Verify the set of streams in aggregate
-    if (!isValidStreamSet(newStreams, stream_config->num_streams)) {
+    if (!isValidStreamSet(newStreams, stream_config->num_streams,
+                          stream_config->operation_mode)) {
         ALOGE("%s:%d: Invalid stream set", __func__, mId);
         goto err_out;
     }
 
-    // Set up all streams (calculate usage/max_buffers for each)
-    setupStreams(newStreams, stream_config->num_streams);
+    // Set up all streams (calculate usage/max_buffers for each,
+    // do any device-specific initialization)
+    res = setupStreams(newStreams, stream_config->num_streams);
+    if (res) {
+        ALOGE("%s:%d: Failed to setup stream set", __func__, mId);
+        goto err_out;
+    }
 
     // Destroy all old streams and replace stream array with new one
     destroyStreams(mStreams, mNumStreams);
@@ -213,7 +220,11 @@
 err_out:
     // Clean up temporary streams, preserve existing mStreams/mNumStreams
     destroyStreams(newStreams, stream_config->num_streams);
-    return -EINVAL;
+    // Set error if it wasn't specified.
+    if (!res) {
+      res = -EINVAL;
+    }
+    return res;
 }
 
 void Camera::destroyStreams(Stream **streams, int count)
@@ -241,7 +252,7 @@
     return priv;
 }
 
-bool Camera::isValidStreamSet(Stream **streams, int count)
+bool Camera::isValidStreamSet(Stream **streams, int count, uint32_t mode)
 {
     int inputs = 0;
     int outputs = 0;
@@ -272,50 +283,37 @@
         ALOGE("%s:%d: Stream config must have <= 1 input", __func__, mId);
         return false;
     }
-    // TODO: check for correct number of Bayer/YUV/JPEG/Encoder streams
-    return true;
+
+    // check for correct number of Bayer/YUV/JPEG/Encoder streams
+    return isSupportedStreamSet(streams, count, mode);
 }
 
-void Camera::setupStreams(Stream **streams, int count)
+int Camera::setupStreams(Stream **streams, int count)
 {
     /*
      * This is where the HAL has to decide internally how to handle all of the
      * streams, and then produce usage and max_buffer values for each stream.
      * Note, the stream array has been checked before this point for ALL invalid
      * conditions, so it must find a successful configuration for this stream
-     * array.  The HAL may not return an error from this point.
-     *
-     * In this demo HAL, we just set all streams to be the same dummy values;
-     * real implementations will want to avoid USAGE_SW_{READ|WRITE}_OFTEN.
+     * array. The only errors should be from individual streams requesting
+     * unsupported features (such as data_space or rotation).
      */
     for (int i = 0; i < count; i++) {
         uint32_t usage = 0;
-
         if (streams[i]->isOutputType())
-            usage |= GRALLOC_USAGE_SW_WRITE_OFTEN |
-                     GRALLOC_USAGE_HW_CAMERA_WRITE;
+            usage |= GRALLOC_USAGE_HW_CAMERA_WRITE;
         if (streams[i]->isInputType())
-            usage |= GRALLOC_USAGE_SW_READ_OFTEN |
-                     GRALLOC_USAGE_HW_CAMERA_READ;
-
+            usage |= GRALLOC_USAGE_HW_CAMERA_READ;
         streams[i]->setUsage(usage);
-        streams[i]->setMaxBuffers(1);
-    }
-}
 
-int Camera::registerStreamBuffers(const camera3_stream_buffer_set_t *buf_set)
-{
-    ALOGV("%s:%d: buffer_set=%p", __func__, mId, buf_set);
-    if (buf_set == NULL) {
-        ALOGE("%s:%d: NULL buffer set", __func__, mId);
-        return -EINVAL;
+        uint32_t max_buffers;
+        int res = setupStream(streams[i], &max_buffers);
+        if (res) {
+          return res;
+        }
+        streams[i]->setMaxBuffers(max_buffers);
     }
-    if (buf_set->stream == NULL) {
-        ALOGE("%s:%d: NULL stream handle", __func__, mId);
-        return -EINVAL;
-    }
-    Stream *stream = reinterpret_cast<Stream*>(buf_set->stream->priv);
-    return stream->registerBuffers(buf_set);
+    return 0;
 }
 
 bool Camera::isValidTemplateType(int type)
@@ -562,13 +560,6 @@
     return camdev_to_camera(dev)->configureStreams(stream_list);
 }
 
-// TODO(b/29221641): remove
-static int register_stream_buffers(const camera3_device_t *dev,
-        const camera3_stream_buffer_set_t *buffer_set)
-{
-    return camdev_to_camera(dev)->registerStreamBuffers(buffer_set);
-}
-
 static const camera_metadata_t *construct_default_request_settings(
         const camera3_device_t *dev, int type)
 {
@@ -588,6 +579,7 @@
 
 static int flush(const camera3_device_t*)
 {
+    // TODO(b/29937783)
     ALOGE("%s: unimplemented.", __func__);
     return -1;
 }
@@ -601,7 +593,7 @@
     .construct_default_request_settings
         = default_camera_hal::construct_default_request_settings,
     .process_capture_request = default_camera_hal::process_capture_request,
-    .get_metadata_vendor_tag_ops = NULL,
+    .get_metadata_vendor_tag_ops = nullptr,
     .dump = default_camera_hal::dump,
     .flush = default_camera_hal::flush,
     .reserved = {0},
diff --git a/modules/camera/3_4/Camera.h b/modules/camera/3_4/Camera.h
index a61cee2..c596350 100644
--- a/modules/camera/3_4/Camera.h
+++ b/modules/camera/3_4/Camera.h
@@ -47,7 +47,6 @@
         // Camera v3 Device Operations (see <hardware/camera3.h>)
         int initialize(const camera3_callback_ops_t *callback_ops);
         int configureStreams(camera3_stream_configuration_t *stream_list);
-        int registerStreamBuffers(const camera3_stream_buffer_set_t *buf_set);
         const camera_metadata_t *constructDefaultRequestSettings(int type);
         int processCaptureRequest(camera3_capture_request_t *request);
         void dump(int fd);
@@ -63,6 +62,12 @@
         // Initialize device info: facing, orientation, resource cost,
         // and conflicting devices (/conflicting devices length)
         virtual void initDeviceInfo(struct camera_info *info) = 0;
+        // Verify stream configuration is device-compatible
+        virtual bool isSupportedStreamSet(Stream** streams, int count,
+                                          uint32_t mode) = 0;
+        // Set up the device for a stream, and get the maximum number of
+        // buffers that stream can handle (max_buffers is an output parameter)
+        virtual int setupStream(Stream* stream, uint32_t* max_buffers) = 0;
         // Verify settings are valid for a capture
         virtual bool isValidCaptureSettings(const camera_metadata_t *) = 0;
         // Separate initialization method for individual devices when opened
@@ -80,9 +85,9 @@
         // Destroy all streams in a stream array, and the array itself
         void destroyStreams(Stream **array, int count);
         // Verify a set of streams is valid in aggregate
-        bool isValidStreamSet(Stream **array, int count);
+        bool isValidStreamSet(Stream **array, int count, uint32_t mode);
         // Calculate usage and max_bufs of each stream
-        void setupStreams(Stream **array, int count);
+        int setupStreams(Stream **array, int count);
         // Copy new settings for re-use and clean up old settings.
         void setSettings(const camera_metadata_t *new_settings);
         // Verify settings are valid for reprocessing an input buffer
diff --git a/modules/camera/3_4/Stream.cpp b/modules/camera/3_4/Stream.cpp
index fdd08d6..0d021ef 100644
--- a/modules/camera/3_4/Stream.cpp
+++ b/modules/camera/3_4/Stream.cpp
@@ -42,17 +42,14 @@
     mHeight(s->height),
     mFormat(s->format),
     mUsage(0),
-    mMaxBuffers(0),
-    mRegistered(false),
-    mBuffers(0),
-    mNumBuffers(0)
+    mRotation(s->rotation),
+    mDataSpace(s->data_space),
+    mMaxBuffers(0)
 {
 }
 
 Stream::~Stream()
 {
-    android::Mutex::Autolock al(mLock);
-    unregisterBuffers_L();
 }
 
 void Stream::setUsage(uint32_t usage)
@@ -61,7 +58,6 @@
     if (usage != mUsage) {
         mUsage = usage;
         mStream->usage = usage;
-        unregisterBuffers_L();
     }
 }
 
@@ -71,22 +67,25 @@
     if (max_buffers != mMaxBuffers) {
         mMaxBuffers = max_buffers;
         mStream->max_buffers = max_buffers;
-        unregisterBuffers_L();
     }
 }
 
-int Stream::getType()
+void Stream::setDataSpace(android_dataspace_t data_space)
 {
-    return mType;
+    android::Mutex::Autolock al(mLock);
+    if (data_space != mDataSpace) {
+        mDataSpace = data_space;
+        mStream->data_space = data_space;
+    }
 }
 
-bool Stream::isInputType()
+bool Stream::isInputType() const
 {
     return mType == CAMERA3_STREAM_INPUT ||
         mType == CAMERA3_STREAM_BIDIRECTIONAL;
 }
 
-bool Stream::isOutputType()
+bool Stream::isOutputType() const
 {
     return mType == CAMERA3_STREAM_OUTPUT ||
         mType == CAMERA3_STREAM_BIDIRECTIONAL;
@@ -145,11 +144,6 @@
     return "Invalid stream format!";
 }
 
-bool Stream::isRegistered()
-{
-    return mRegistered;
-}
-
 bool Stream::isValidReuseStream(int id, camera3_stream_t *s)
 {
     if (id != mId) {
@@ -187,40 +181,6 @@
     return true;
 }
 
-int Stream::registerBuffers(const camera3_stream_buffer_set_t *buf_set)
-{
-    ATRACE_CALL();
-    android::Mutex::Autolock al(mLock);
-
-    if (buf_set->stream != mStream) {
-        ALOGE("%s:%d: Buffer set for invalid stream. Got %p expect %p",
-                __func__, mId, buf_set->stream, mStream);
-        return -EINVAL;
-    }
-
-    mNumBuffers = buf_set->num_buffers;
-    mBuffers = new buffer_handle_t*[mNumBuffers];
-
-    for (unsigned int i = 0; i < mNumBuffers; i++) {
-        ALOGV("%s:%d: Registering buffer %p", __func__, mId,
-                buf_set->buffers[i]);
-        mBuffers[i] = buf_set->buffers[i];
-        // TODO: register buffers with hw, handle error cases
-    }
-    mRegistered = true;
-
-    return 0;
-}
-
-// This must only be called with mLock held
-void Stream::unregisterBuffers_L()
-{
-    mRegistered = false;
-    mNumBuffers = 0;
-    delete [] mBuffers;
-    // TODO: unregister buffers from hw
-}
-
 void Stream::dump(int fd)
 {
     android::Mutex::Autolock al(mLock);
@@ -231,13 +191,9 @@
     dprintf(fd, "Stream Format: %s (%d)", formatToString(mFormat), mFormat);
     // ToDo: prettyprint usage mask flags
     dprintf(fd, "Gralloc Usage Mask: %#" PRIx32 "\n", mUsage);
+    dprintf(fd, "Stream Rotation: %d\n", mRotation);
+    dprintf(fd, "Stream Dataspace: 0x%x\n", mDataSpace);
     dprintf(fd, "Max Buffer Count: %" PRIu32 "\n", mMaxBuffers);
-    dprintf(fd, "Buffers Registered: %s\n", mRegistered ? "true" : "false");
-    dprintf(fd, "Number of Buffers: %" PRIu32 "\n", mNumBuffers);
-    for (uint32_t i = 0; i < mNumBuffers; i++) {
-        dprintf(fd, "Buffer %" PRIu32 "/%" PRIu32 ": %p\n", i, mNumBuffers,
-                mBuffers[i]);
-    }
 }
 
 } // namespace default_camera_hal
diff --git a/modules/camera/3_4/Stream.h b/modules/camera/3_4/Stream.h
index 2187f2b..1531b12 100644
--- a/modules/camera/3_4/Stream.h
+++ b/modules/camera/3_4/Stream.h
@@ -34,16 +34,18 @@
         // validate that astream's parameters match this stream's parameters
         bool isValidReuseStream(int id, camera3_stream_t *s);
 
-        // Register buffers with hardware
-        int registerBuffers(const camera3_stream_buffer_set_t *buf_set);
-
         void setUsage(uint32_t usage);
         void setMaxBuffers(uint32_t max_buffers);
+        void setDataSpace(android_dataspace_t data_space);
 
-        int getType();
-        bool isInputType();
-        bool isOutputType();
-        bool isRegistered();
+        inline int getFormat() const { return mFormat; };
+        inline int getType() const { return mType; };
+        inline uint32_t getWidth() const { return mWidth; };
+        inline uint32_t getHeight() const { return mHeight; };
+        inline int getRotation() const { return mRotation; };
+
+        bool isInputType() const;
+        bool isOutputType() const;
         const char* typeToString(int type);
         const char* formatToString(int format);
         void dump(int fd);
@@ -52,8 +54,6 @@
         bool mReuse;
 
     private:
-        // Clean up buffer state. must be called with mLock held.
-        void unregisterBuffers_L();
 
         // The camera device id this stream belongs to
         const int mId;
@@ -69,14 +69,12 @@
         const int mFormat;
         // Gralloc usage mask : GRALLOC_USAGE_* (see <hardware/gralloc.h>)
         uint32_t mUsage;
+        // Output rotation this stream should undergo
+        const int mRotation;
+        // Color space of image data.
+        android_dataspace_t mDataSpace;
         // Max simultaneous in-flight buffers for this stream
         uint32_t mMaxBuffers;
-        // Buffers have been registered for this stream and are ready
-        bool mRegistered;
-        // Array of handles to buffers currently in use by the stream
-        buffer_handle_t **mBuffers;
-        // Number of buffers in mBuffers
-        unsigned int mNumBuffers;
         // Lock protecting the Stream object for modifications
         android::Mutex mLock;
 };
diff --git a/modules/camera/3_4/V4L2Camera.cpp b/modules/camera/3_4/V4L2Camera.cpp
index b3ae4fc..289a2cf 100644
--- a/modules/camera/3_4/V4L2Camera.cpp
+++ b/modules/camera/3_4/V4L2Camera.cpp
@@ -49,6 +49,10 @@
 V4L2Camera::V4L2Camera(int id, std::string path)
     : default_camera_hal::Camera(id),
       mDevicePath(std::move(path)),
+      mOutStreamFormat(0),
+      mOutStreamWidth(0),
+      mOutStreamHeight(0),
+      mOutStreamMaxBuffers(0),
       mTemplatesInitialized(false),
       mCharacteristicsInitialized(false) {
   HAL_LOG_ENTER();
@@ -58,6 +62,16 @@
   HAL_LOG_ENTER();
 }
 
+// Helper function. Should be used instead of ioctl throughout this class.
+template<typename T>
+int V4L2Camera::ioctlLocked(int request, T data) {
+  android::Mutex::Autolock al(mDeviceLock);
+  if (mDeviceFd.get() < 0) {
+    return -ENODEV;
+  }
+  return TEMP_FAILURE_RETRY(ioctl(mDeviceFd.get(), request, data));
+}
+
 int V4L2Camera::connect() {
   HAL_LOG_ENTER();
 
@@ -381,17 +395,19 @@
 
   /* android.request. */
 
-  // Resources may be an issue, so just using minimum allowable
-  // for LIMITED devices.
   int32_t max_num_output_streams[] = {
-    /*Raw*/0, /*YUV*/2, /*JPEG*/1};
+    mMaxRawOutputStreams, mMaxYuvOutputStreams, mMaxJpegOutputStreams};
   res = info.update(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
                     max_num_output_streams, ARRAY_SIZE(max_num_output_streams));
   if (res != android::OK) {
     return res;
   }
 
-  // Reprocessing not supported, so no maxNumInputStreams.
+  res = info.update(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
+                    &mMaxInputStreams, 1);
+  if (res != android::OK) {
+    return res;
+  }
 
   // No way to know for V4L2, so fake with max allowable latency.
   // Doesn't mean much without per-frame controls.
@@ -1170,6 +1186,180 @@
   return 0;
 }
 
+bool V4L2Camera::isSupportedStreamSet(default_camera_hal::Stream** streams,
+                                      int count, uint32_t mode) {
+  HAL_LOG_ENTER();
+
+  if (mode != CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE) {
+    HAL_LOGE("Unsupported stream configuration mode: %d", mode);
+    return false;
+  }
+
+  // This should be checked by the caller, but put here as a sanity check.
+  if (count < 1) {
+    HAL_LOGE("Must request at least 1 stream");
+    return false;
+  }
+
+  // Count the number of streams of each type.
+  int32_t num_input = 0;
+  int32_t num_raw = 0;
+  int32_t num_yuv = 0;
+  int32_t num_jpeg = 0;
+  for (int i = 0; i < count; ++i) {
+    default_camera_hal::Stream* stream = streams[i];
+
+    if (stream->isInputType()) {
+      ++num_input;
+    }
+
+    if (stream->isOutputType()) {
+      switch (halToV4L2PixelFormat(stream->getFormat())) {
+        case V4L2_PIX_FMT_YUV420:
+          ++num_yuv;
+          break;
+        case V4L2_PIX_FMT_JPEG:
+          ++num_jpeg;
+          break;
+        default:
+          // Note: no supported raw formats at this time.
+          HAL_LOGE("Unsupported format for stream %d: %d", i, stream->getFormat());
+          return false;
+      }
+    }
+  }
+
+  if (num_input > mMaxInputStreams || num_raw > mMaxRawOutputStreams ||
+      num_yuv > mMaxYuvOutputStreams || num_jpeg > mMaxJpegOutputStreams) {
+    HAL_LOGE("Invalid stream configuration: %d input, %d RAW, %d YUV, %d JPEG "
+             "(max supported: %d input, %d RAW, %d YUV, %d JPEG)",
+             mMaxInputStreams, mMaxRawOutputStreams, mMaxYuvOutputStreams,
+             mMaxJpegOutputStreams, num_input, num_raw, num_yuv, num_jpeg);
+    return false;
+  }
+
+  // TODO(b/29939583): The above logic should be all that's necessary,
+  // but V4L2 doesn't actually support more than 1 stream at a time. So for now,
+  // if not all streams are the same format and size, error. Note that this
+  // means the HAL is not spec-compliant; the requested streams are technically
+  // valid and it is not technically allowed to error once it has reached this
+  // point.
+  int format = streams[0]->getFormat();
+  uint32_t width = streams[0]->getWidth();
+  uint32_t height = streams[0]->getHeight();
+  for (int i = 1; i < count; ++i) {
+    const default_camera_hal::Stream* stream = streams[i];
+    if (stream->getFormat() != format || stream->getWidth() != width ||
+        stream->getHeight() != height) {
+      HAL_LOGE("V4L2 only supports 1 stream configuration at a time "
+               "(stream 0 is format %d, width %u, height %u, "
+               "stream %d is format %d, width %u, height %u).",
+               format, width, height, i, stream->getFormat(),
+               stream->getWidth(), stream->getHeight());
+      return false;
+    }
+  }
+
+  return true;
+}
+
+int V4L2Camera::setupStream(default_camera_hal::Stream* stream,
+                            uint32_t* max_buffers) {
+  HAL_LOG_ENTER();
+
+  if (stream->getRotation() != CAMERA3_STREAM_ROTATION_0) {
+    HAL_LOGE("Rotation %d not supported", stream->getRotation());
+    return -EINVAL;
+  }
+
+  // Doesn't matter what was requested, we always use dataspace V0_JFIF.
+  // Note: according to camera3.h, this isn't allowed, but etalvala@google.com
+  // claims it's underdocumented; the implementation lets the HAL overwrite it.
+  stream->setDataSpace(HAL_DATASPACE_V0_JFIF);
+
+  int ret = setFormat(stream);
+  if (ret) {
+    return ret;
+  }
+
+  // Only do buffer setup if we don't know our maxBuffers.
+  if (mOutStreamMaxBuffers < 1) {
+    ret = setupBuffers();
+    if (ret) {
+      return ret;
+    }
+  }
+
+  // Sanity check.
+  if (mOutStreamMaxBuffers < 1) {
+    HAL_LOGE("HAL failed to determine max number of buffers.");
+    return -ENODEV;
+  }
+  *max_buffers = mOutStreamMaxBuffers;
+
+  return 0;
+}
+
+int V4L2Camera::setFormat(const default_camera_hal::Stream* stream) {
+  HAL_LOG_ENTER();
+
+  // Should be checked earlier; sanity check.
+  if (stream->isInputType()) {
+    HAL_LOGE("Input streams not supported.");
+    return -EINVAL;
+  }
+
+  v4l2_format format;
+  memset(&format, 0, sizeof(format));
+  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  format.fmt.pix.width = stream->getWidth();
+  format.fmt.pix.height = stream->getHeight();
+  format.fmt.pix.pixelformat = halToV4L2PixelFormat(stream->getFormat());
+  // Check to make sure we're not already in the correct format.
+  if (mOutStreamFormat == format.fmt.pix.pixelformat &&
+      mOutStreamWidth == format.fmt.pix.width &&
+      mOutStreamHeight == format.fmt.pix.height) {
+    return 0;
+  }
+  // Not in the correct format, set our format.
+  int ret = ioctlLocked(VIDIOC_S_FMT, &format);
+  if (ret < 0) {
+    HAL_LOGE("S_FMT failed: %s", strerror(errno));
+    return -ENODEV;
+  }
+  // Check that the driver actually set to the requested values.
+  if (format.fmt.pix.pixelformat != halToV4L2PixelFormat(stream->getFormat()) ||
+      format.fmt.pix.width != stream->getWidth() ||
+      format.fmt.pix.height != stream->getHeight()) {
+    HAL_LOGE("Device doesn't support desired stream configuration.");
+    return -EINVAL;
+  }
+  // Since our format changed, our maxBuffers may be incorrect.
+  mOutStreamMaxBuffers = 0;
+
+  return 0;
+}
+
+int V4L2Camera::setupBuffers() {
+  HAL_LOG_ENTER();
+
+  // "Request" a buffer (since we're using a userspace buffer, this just
+  // tells V4L2 to switch into userspace buffer mode).
+  v4l2_requestbuffers req_buffers;
+  memset(&req_buffers, 0, sizeof(req_buffers));
+  req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+  req_buffers.memory = V4L2_MEMORY_USERPTR;
+  req_buffers.count = 1;
+  if (ioctlLocked(VIDIOC_REQBUFS, &req_buffers) < 0) {
+    HAL_LOGE("REQBUFS failed: %s", strerror(errno));
+    return -ENODEV;
+  }
+
+  // V4L2 will set req_buffers.count to a number of buffers it can handle.
+  mOutStreamMaxBuffers = req_buffers.count;
+  return 0;
+}
+
 bool V4L2Camera::isValidCaptureSettings(const camera_metadata_t* settings) {
   HAL_LOG_ENTER();
 
@@ -1227,6 +1417,14 @@
   // TODO(b/29394024): query V4L2_CID_FOCUS_ABSOLUTE for focus range.
   mFocusDistance = 0;  // Fixed focus.
 
+  // TODO(b/29939583): V4L2 can only support 1 stream at a time.
+  // For now, just reporting minimum allowable for LIMITED devices.
+  mMaxRawOutputStreams = 0;
+  mMaxYuvOutputStreams = 2;
+  mMaxJpegOutputStreams = 1;
+  // Reprocessing not supported.
+  mMaxInputStreams = 0;
+
   /* Features with (potentially) multiple options. */
 
   // TODO(b/29394024): query V4L2_CID_EXPOSURE_AUTO for ae modes.
@@ -1272,23 +1470,15 @@
   // Need to support YUV_420_888 and JPEG.
   // TODO(b/29394024): query VIDIOC_ENUM_FMT.
   std::vector<uint32_t> formats = {{V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420}};
-  int32_t hal_format;
   // We want to find the smallest maximum frame duration amongst formats.
   mMaxFrameDuration = std::numeric_limits<int64_t>::max();
   int64_t min_yuv_frame_duration = std::numeric_limits<int64_t>::max();
   for (auto format : formats) {
-    // Translate V4L2 format to HAL format.
-    switch (format) {
-      case V4L2_PIX_FMT_JPEG:
-        hal_format = HAL_PIXEL_FORMAT_BLOB;
-        break;
-      case V4L2_PIX_FMT_YUV420:
-        hal_format = HAL_PIXEL_FORMAT_YCbCr_420_888;
-      default:
-        // Unrecognized/unused format. Skip it.
-        continue;
+    int32_t hal_format = V4L2ToHalPixelFormat(format);
+    if (hal_format < 0) {
+      // Unrecognized/unused format. Skip it.
+      continue;
     }
-
     // TODO(b/29394024): query VIDIOC_ENUM_FRAMESIZES.
     // For now, just 640x480.
     ArrayVector<int32_t, 2> frame_sizes;
@@ -1354,4 +1544,39 @@
   return 0;
 }
 
+int V4L2Camera::V4L2ToHalPixelFormat(uint32_t v4l2_format) {
+  // Translate V4L2 format to HAL format.
+  int hal_format = -1;
+  switch (v4l2_format) {
+    case V4L2_PIX_FMT_JPEG:
+      hal_format = HAL_PIXEL_FORMAT_BLOB;
+      break;
+    case V4L2_PIX_FMT_YUV420:
+      hal_format = HAL_PIXEL_FORMAT_YCbCr_420_888;
+      break;
+    default:
+      // Unrecognized format.
+      break;
+  }
+  return hal_format;
+}
+
+uint32_t V4L2Camera::halToV4L2PixelFormat(int hal_format) {
+  // Translate HAL format to V4L2 format.
+  uint32_t v4l2_format = 0;
+  switch (hal_format) {
+    case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:  // fall-through.
+    case HAL_PIXEL_FORMAT_YCbCr_420_888:
+      v4l2_format = V4L2_PIX_FMT_YUV420;
+      break;
+    case HAL_PIXEL_FORMAT_BLOB:
+      v4l2_format = V4L2_PIX_FMT_JPEG;
+      break;
+    default:
+      // Unrecognized format.
+      break;
+  }
+  return v4l2_format;
+}
+
 } // namespace v4l2_camera_hal
diff --git a/modules/camera/3_4/V4L2Camera.h b/modules/camera/3_4/V4L2Camera.h
index 7aece03..e57c5b8 100644
--- a/modules/camera/3_4/V4L2Camera.h
+++ b/modules/camera/3_4/V4L2Camera.h
@@ -53,13 +53,39 @@
   void initDeviceInfo(camera_info_t* info) override;
   // Initialize whole device (templates/etc) when opened.
   int initDevice() override;
+  // Verify stream configuration is device-compatible.
+  bool isSupportedStreamSet(default_camera_hal::Stream** streams,
+                            int count, uint32_t mode) override;
+  // Set up the device for a stream, and get the maximum number of
+  // buffers that stream can handle (max_buffers is an output parameter).
+  int setupStream(default_camera_hal::Stream* stream,
+                  uint32_t* max_buffers) override;
   // Verify settings are valid for a capture with this device.
   bool isValidCaptureSettings(const camera_metadata_t* settings) override;
 
+  // Helper functions for V4L2 functionality.
+  int setFormat(const default_camera_hal::Stream* stream);
+  int setupBuffers();
+
+  // HAL <-> V4L2 conversions.
+  uint32_t halToV4L2PixelFormat(int hal_format);  // 0 for unrecognized.
+  int V4L2ToHalPixelFormat(uint32_t v4l2_format);  // -1 for unrecognized.
+
   // The camera device path. For example, /dev/video0.
   const std::string mDevicePath;
   // The opened device fd.
   ScopedFd mDeviceFd;
+  // Lock protecting use of the device.
+  android::Mutex mDeviceLock;
+  // Wrapper around ioctl.
+  template<typename T>
+  int ioctlLocked(int request, T data);
+
+  // Current output stream settings.
+  uint32_t mOutStreamFormat;
+  uint32_t mOutStreamWidth;
+  uint32_t mOutStreamHeight;
+  uint32_t mOutStreamMaxBuffers;
 
   bool mTemplatesInitialized;
   int initTemplates();
@@ -81,6 +107,11 @@
   uint8_t mAwbLockAvailable;
   uint8_t mFlashAvailable;
   float mFocusDistance;
+  int32_t mMaxRawOutputStreams;
+  int32_t mMaxYuvOutputStreams;
+  int32_t mMaxJpegOutputStreams;
+  int32_t mMaxInputStreams;
+  std::vector<int32_t> mSupportedFormats;
   // Variable characteristics available options.
   std::vector<uint8_t> mAeModes;
   std::vector<uint8_t> mAeAntibandingModes;