Avichal Rakesh | e1857f8 | 2022-06-08 17:47:23 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2022 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICESESSION_H_ |
| 18 | #define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICESESSION_H_ |
| 19 | |
| 20 | #include <ExternalCameraUtils.h> |
| 21 | #include <SimpleThread.h> |
| 22 | #include <aidl/android/hardware/camera/common/Status.h> |
| 23 | #include <aidl/android/hardware/camera/device/BnCameraDeviceSession.h> |
| 24 | #include <aidl/android/hardware/camera/device/BufferRequest.h> |
| 25 | #include <aidl/android/hardware/camera/device/Stream.h> |
| 26 | #include <android-base/unique_fd.h> |
| 27 | #include <fmq/AidlMessageQueue.h> |
| 28 | #include <utils/Thread.h> |
| 29 | #include <deque> |
| 30 | #include <list> |
| 31 | |
| 32 | namespace android { |
| 33 | namespace hardware { |
| 34 | namespace camera { |
| 35 | namespace device { |
| 36 | namespace implementation { |
| 37 | |
| 38 | using ::aidl::android::hardware::camera::common::Status; |
| 39 | using ::aidl::android::hardware::camera::device::BnCameraDeviceSession; |
| 40 | using ::aidl::android::hardware::camera::device::BufferCache; |
| 41 | using ::aidl::android::hardware::camera::device::BufferRequest; |
| 42 | using ::aidl::android::hardware::camera::device::CameraMetadata; |
| 43 | using ::aidl::android::hardware::camera::device::CameraOfflineSessionInfo; |
| 44 | using ::aidl::android::hardware::camera::device::CaptureRequest; |
| 45 | using ::aidl::android::hardware::camera::device::HalStream; |
| 46 | using ::aidl::android::hardware::camera::device::ICameraDeviceCallback; |
| 47 | using ::aidl::android::hardware::camera::device::ICameraOfflineSession; |
| 48 | using ::aidl::android::hardware::camera::device::RequestTemplate; |
| 49 | using ::aidl::android::hardware::camera::device::Stream; |
| 50 | using ::aidl::android::hardware::camera::device::StreamConfiguration; |
| 51 | using ::aidl::android::hardware::common::fmq::MQDescriptor; |
| 52 | using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite; |
| 53 | using ::android::AidlMessageQueue; |
| 54 | using ::android::base::unique_fd; |
| 55 | using ::android::hardware::camera::common::helper::SimpleThread; |
| 56 | using ::android::hardware::camera::external::common::ExternalCameraConfig; |
| 57 | using ::android::hardware::camera::external::common::SizeHasher; |
| 58 | using ::ndk::ScopedAStatus; |
| 59 | |
| 60 | class ExternalCameraDeviceSession : public BnCameraDeviceSession, public OutputThreadInterface { |
| 61 | public: |
| 62 | ExternalCameraDeviceSession(const std::shared_ptr<ICameraDeviceCallback>&, |
| 63 | const ExternalCameraConfig& cfg, |
| 64 | const std::vector<SupportedV4L2Format>& sortedFormats, |
| 65 | const CroppingType& croppingType, |
| 66 | const common::V1_0::helper::CameraMetadata& chars, |
| 67 | const std::string& cameraId, unique_fd v4l2Fd); |
| 68 | ~ExternalCameraDeviceSession() override; |
| 69 | |
| 70 | // Caller must use this method to check if CameraDeviceSession ctor failed |
| 71 | bool isInitFailed(); |
| 72 | bool isClosed(); |
| 73 | |
| 74 | ScopedAStatus close() override; |
| 75 | |
| 76 | ScopedAStatus configureStreams(const StreamConfiguration& in_requestedConfiguration, |
| 77 | std::vector<HalStream>* _aidl_return) override; |
| 78 | ScopedAStatus constructDefaultRequestSettings(RequestTemplate in_type, |
| 79 | CameraMetadata* _aidl_return) override; |
| 80 | ScopedAStatus flush() override; |
| 81 | ScopedAStatus getCaptureRequestMetadataQueue( |
| 82 | MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override; |
| 83 | ScopedAStatus getCaptureResultMetadataQueue( |
| 84 | MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override; |
| 85 | ScopedAStatus isReconfigurationRequired(const CameraMetadata& in_oldSessionParams, |
| 86 | const CameraMetadata& in_newSessionParams, |
| 87 | bool* _aidl_return) override; |
| 88 | ScopedAStatus processCaptureRequest(const std::vector<CaptureRequest>& in_requests, |
| 89 | const std::vector<BufferCache>& in_cachesToRemove, |
| 90 | int32_t* _aidl_return) override; |
| 91 | ScopedAStatus signalStreamFlush(const std::vector<int32_t>& in_streamIds, |
| 92 | int32_t in_streamConfigCounter) override; |
| 93 | ScopedAStatus switchToOffline(const std::vector<int32_t>& in_streamsToKeep, |
| 94 | CameraOfflineSessionInfo* out_offlineSessionInfo, |
| 95 | std::shared_ptr<ICameraOfflineSession>* _aidl_return) override; |
| 96 | ScopedAStatus repeatingRequestEnd(int32_t in_frameNumber, |
| 97 | const std::vector<int32_t>& in_streamIds) override; |
| 98 | |
| 99 | Status importBuffer(int32_t streamId, uint64_t bufId, buffer_handle_t buf, |
| 100 | buffer_handle_t** outBufPtr) override; |
| 101 | |
| 102 | void notifyError(int32_t frameNumber, int32_t streamId, ErrorCode ec) override; |
| 103 | |
| 104 | Status processCaptureRequestError(const std::shared_ptr<HalRequest>& ptr, |
| 105 | std::vector<NotifyMsg>* msgs, |
| 106 | std::vector<CaptureResult>* results) override; |
| 107 | |
| 108 | Status processCaptureResult(std::shared_ptr<HalRequest>& ptr) override; |
| 109 | ssize_t getJpegBufferSize(int32_t width, int32_t height) const override; |
| 110 | |
| 111 | // Called by CameraDevice to dump active device states |
| 112 | binder_status_t dump(int fd, const char** args, uint32_t numArgs) override; |
| 113 | |
| 114 | static Status isStreamCombinationSupported( |
| 115 | const StreamConfiguration& config, |
| 116 | const std::vector<SupportedV4L2Format>& supportedFormats, |
| 117 | const ExternalCameraConfig& devCfg); |
| 118 | |
| 119 | static const int kMaxProcessedStream = 2; |
| 120 | static const int kMaxStallStream = 1; |
| 121 | static const uint32_t kMaxBytesPerPixel = 2; |
| 122 | |
| 123 | class BufferRequestThread : public SimpleThread { |
| 124 | public: |
| 125 | BufferRequestThread(std::weak_ptr<OutputThreadInterface> parent, |
| 126 | std::shared_ptr<ICameraDeviceCallback> callbacks); |
| 127 | |
| 128 | int requestBufferStart(const std::vector<HalStreamBuffer>&); |
| 129 | int waitForBufferRequestDone( |
| 130 | /*out*/ std::vector<HalStreamBuffer>*); |
| 131 | |
| 132 | bool threadLoop() override; |
| 133 | |
| 134 | private: |
| 135 | void waitForNextRequest(); |
| 136 | |
| 137 | const std::weak_ptr<OutputThreadInterface> mParent; |
| 138 | const std::shared_ptr<ICameraDeviceCallback> mCallbacks; |
| 139 | |
| 140 | std::mutex mLock; |
| 141 | bool mRequestingBuffer = false; |
| 142 | |
| 143 | std::vector<HalStreamBuffer> mBufferReqs; |
| 144 | std::vector<HalStreamBuffer> mPendingReturnBufferReqs; |
| 145 | // mHalBufferReqs is not under mLock protection during the HIDL transaction |
| 146 | std::vector<BufferRequest> mHalBufferReqs; |
| 147 | |
| 148 | // request buffers takes much less time in steady state, but can take much longer |
| 149 | // when requesting 1st buffer from a stream. |
| 150 | // TODO: consider a separate timeout for new vs. steady state? |
| 151 | // TODO: or make sure framework is warming up the pipeline during configure new stream? |
| 152 | static const int kReqProcTimeoutMs = 66; |
| 153 | |
| 154 | static const int kReqWaitTimeoutMs = 33; |
| 155 | static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec |
| 156 | std::condition_variable mRequestCond; // signaled when a new buffer request incoming |
| 157 | std::condition_variable mRequestDoneCond; // signaled when a request is done |
| 158 | }; |
| 159 | |
| 160 | class OutputThread : public SimpleThread { |
| 161 | public: |
| 162 | OutputThread(std::weak_ptr<OutputThreadInterface> parent, CroppingType, |
| 163 | const common::V1_0::helper::CameraMetadata&, |
| 164 | std::shared_ptr<BufferRequestThread> bufReqThread); |
| 165 | ~OutputThread(); |
| 166 | |
| 167 | Status allocateIntermediateBuffers(const Size& v4lSize, const Size& thumbSize, |
| 168 | const std::vector<Stream>& streams, |
| 169 | uint32_t blobBufferSize); |
| 170 | Status submitRequest(const std::shared_ptr<HalRequest>&); |
| 171 | void flush(); |
| 172 | void dump(int fd); |
| 173 | bool threadLoop() override; |
| 174 | |
| 175 | void setExifMakeModel(const std::string& make, const std::string& model); |
| 176 | |
| 177 | // The remaining request list is returned for offline processing |
| 178 | std::list<std::shared_ptr<HalRequest>> switchToOffline(); |
| 179 | |
| 180 | protected: |
| 181 | static const int kFlushWaitTimeoutSec = 3; // 3 sec |
| 182 | static const int kReqWaitTimeoutMs = 33; // 33ms |
| 183 | static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec |
| 184 | |
| 185 | // Methods to request output buffer in parallel |
| 186 | int requestBufferStart(const std::vector<HalStreamBuffer>&); |
| 187 | int waitForBufferRequestDone( |
| 188 | /*out*/ std::vector<HalStreamBuffer>*); |
| 189 | |
| 190 | void waitForNextRequest(std::shared_ptr<HalRequest>* out); |
| 191 | void signalRequestDone(); |
| 192 | |
| 193 | int cropAndScaleLocked(std::shared_ptr<AllocatedFrame>& in, const Size& outSize, |
| 194 | YCbCrLayout* out); |
| 195 | |
| 196 | int cropAndScaleThumbLocked(std::shared_ptr<AllocatedFrame>& in, const Size& outSize, |
| 197 | YCbCrLayout* out); |
| 198 | |
| 199 | int createJpegLocked(HalStreamBuffer& halBuf, |
| 200 | const common::V1_0::helper::CameraMetadata& settings); |
| 201 | |
| 202 | void clearIntermediateBuffers(); |
| 203 | |
| 204 | const std::weak_ptr<OutputThreadInterface> mParent; |
| 205 | const CroppingType mCroppingType; |
| 206 | const common::V1_0::helper::CameraMetadata mCameraCharacteristics; |
| 207 | |
| 208 | mutable std::mutex mRequestListLock; // Protect access to mRequestList, |
| 209 | // mProcessingRequest and mProcessingFrameNumber |
| 210 | std::condition_variable mRequestCond; // signaled when a new request is submitted |
| 211 | std::condition_variable mRequestDoneCond; // signaled when a request is done processing |
| 212 | std::list<std::shared_ptr<HalRequest>> mRequestList; |
| 213 | bool mProcessingRequest = false; |
| 214 | uint32_t mProcessingFrameNumber = 0; |
| 215 | |
| 216 | // V4L2 frameIn |
| 217 | // (MJPG decode)-> mYu12Frame |
| 218 | // (Scale)-> mScaledYu12Frames |
| 219 | // (Format convert) -> output gralloc frames |
| 220 | mutable std::mutex mBufferLock; // Protect access to intermediate buffers |
| 221 | std::shared_ptr<AllocatedFrame> mYu12Frame; |
| 222 | std::shared_ptr<AllocatedFrame> mYu12ThumbFrame; |
| 223 | std::unordered_map<Size, std::shared_ptr<AllocatedFrame>, SizeHasher> mIntermediateBuffers; |
| 224 | std::unordered_map<Size, std::shared_ptr<AllocatedFrame>, SizeHasher> mScaledYu12Frames; |
| 225 | YCbCrLayout mYu12FrameLayout; |
| 226 | YCbCrLayout mYu12ThumbFrameLayout; |
| 227 | std::vector<uint8_t> mMuteTestPatternFrame; |
| 228 | uint32_t mTestPatternData[4] = {0, 0, 0, 0}; |
| 229 | bool mCameraMuted = false; |
| 230 | uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size |
| 231 | |
| 232 | std::string mExifMake; |
| 233 | std::string mExifModel; |
| 234 | |
| 235 | const std::shared_ptr<BufferRequestThread> mBufferRequestThread; |
| 236 | }; |
| 237 | |
| 238 | private: |
| 239 | bool initialize(); |
| 240 | // To init/close different version of output thread |
| 241 | void initOutputThread(); |
| 242 | void closeOutputThread(); |
| 243 | void closeOutputThreadImpl(); |
| 244 | |
| 245 | void close(bool callerIsDtor); |
| 246 | Status initStatus() const; |
| 247 | status_t initDefaultRequests(); |
| 248 | |
| 249 | status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp); |
| 250 | int configureV4l2StreamLocked(const SupportedV4L2Format& fmt, double fps = 0.0); |
| 251 | int v4l2StreamOffLocked(); |
| 252 | |
| 253 | int setV4l2FpsLocked(double fps); |
| 254 | |
| 255 | std::unique_ptr<V4L2Frame> dequeueV4l2FrameLocked( |
| 256 | /*out*/ nsecs_t* shutterTs); // Called with mLock held |
| 257 | |
| 258 | void enqueueV4l2Frame(const std::shared_ptr<V4L2Frame>&); |
| 259 | |
| 260 | // Check if input Stream is one of supported stream setting on this device |
| 261 | static bool isSupported(const Stream& stream, |
| 262 | const std::vector<SupportedV4L2Format>& supportedFormats, |
| 263 | const ExternalCameraConfig& cfg); |
| 264 | |
| 265 | // Validate and import request's output buffers and acquire fence |
| 266 | Status importRequestLocked(const CaptureRequest& request, |
| 267 | std::vector<buffer_handle_t*>& allBufPtrs, |
| 268 | std::vector<int>& allFences); |
| 269 | |
| 270 | Status importRequestLockedImpl(const CaptureRequest& request, |
| 271 | std::vector<buffer_handle_t*>& allBufPtrs, |
| 272 | std::vector<int>& allFences); |
| 273 | |
| 274 | Status importBufferLocked(int32_t streamId, uint64_t bufId, buffer_handle_t buf, |
| 275 | /*out*/ buffer_handle_t** outBufPtr); |
| 276 | static void cleanupInflightFences(std::vector<int>& allFences, size_t numFences); |
| 277 | void cleanupBuffersLocked(int id); |
| 278 | |
| 279 | void updateBufferCaches(const std::vector<BufferCache>& cachesToRemove); |
| 280 | |
| 281 | Status processOneCaptureRequest(const CaptureRequest& request); |
| 282 | void notifyShutter(int32_t frameNumber, nsecs_t shutterTs); |
| 283 | |
| 284 | void invokeProcessCaptureResultCallback(std::vector<CaptureResult>& results, bool tryWriteFmq); |
| 285 | Size getMaxJpegResolution() const; |
| 286 | |
| 287 | Size getMaxThumbResolution() const; |
| 288 | |
| 289 | int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk); |
| 290 | |
| 291 | // Main body of switchToOffline. This method does not invoke any callbacks |
| 292 | // but instead returns the necessary callbacks in output arguments so callers |
| 293 | // can callback later without holding any locks |
| 294 | Status switchToOffline(const std::vector<int32_t>& offlineStreams, |
| 295 | /*out*/ std::vector<NotifyMsg>* msgs, |
| 296 | /*out*/ std::vector<CaptureResult>* results, |
| 297 | /*out*/ CameraOfflineSessionInfo* info, |
| 298 | /*out*/ std::shared_ptr<ICameraOfflineSession>* session); |
| 299 | |
| 300 | bool supportOfflineLocked(int32_t streamId); |
| 301 | |
| 302 | // Whether a request can be completely dropped when switching to offline |
| 303 | bool canDropRequest(const std::vector<int32_t>& offlineStreams, |
| 304 | std::shared_ptr<HalRequest> halReq); |
| 305 | |
| 306 | void fillOfflineSessionInfo(const std::vector<int32_t>& offlineStreams, |
| 307 | std::deque<std::shared_ptr<HalRequest>>& offlineReqs, |
| 308 | const std::map<int, CirculatingBuffers>& circulatingBuffers, |
| 309 | /*out*/ CameraOfflineSessionInfo* info); |
| 310 | |
| 311 | // Protect (most of) HIDL interface methods from synchronized-entering |
| 312 | mutable Mutex mInterfaceLock; |
| 313 | |
| 314 | mutable Mutex mLock; // Protect all private members except otherwise noted |
| 315 | const std::shared_ptr<ICameraDeviceCallback> mCallback; |
| 316 | const ExternalCameraConfig& mCfg; |
| 317 | const common::V1_0::helper::CameraMetadata mCameraCharacteristics; |
| 318 | const std::vector<SupportedV4L2Format> mSupportedFormats; |
| 319 | const CroppingType mCroppingType; |
| 320 | const std::string mCameraId; |
| 321 | |
| 322 | // Not protected by mLock, this is almost a const. |
| 323 | // Setup in constructor, reset in close() after OutputThread is joined |
| 324 | unique_fd mV4l2Fd; |
| 325 | |
| 326 | // device is closed either |
| 327 | // - closed by user |
| 328 | // - init failed |
| 329 | // - camera disconnected |
| 330 | bool mClosed = false; |
| 331 | bool mInitialized = false; |
| 332 | bool mInitFail = false; |
| 333 | bool mFirstRequest = false; |
| 334 | common::V1_0::helper::CameraMetadata mLatestReqSetting; |
| 335 | |
| 336 | bool mV4l2Streaming = false; |
| 337 | SupportedV4L2Format mV4l2StreamingFmt; |
| 338 | double mV4l2StreamingFps = 0.0; |
| 339 | size_t mV4L2BufferCount = 0; |
| 340 | |
| 341 | static const int kBufferWaitTimeoutSec = 3; // TODO: handle long exposure (or not allowing) |
| 342 | std::mutex mV4l2BufferLock; // protect the buffer count and condition below |
| 343 | std::condition_variable mV4L2BufferReturned; |
| 344 | size_t mNumDequeuedV4l2Buffers = 0; |
| 345 | uint32_t mMaxV4L2BufferSize = 0; |
| 346 | |
| 347 | // Not protected by mLock (but might be used when mLock is locked) |
| 348 | std::shared_ptr<OutputThread> mOutputThread; |
| 349 | |
| 350 | // Stream ID -> Stream cache |
| 351 | std::unordered_map<int, Stream> mStreamMap; |
| 352 | |
| 353 | std::mutex mInflightFramesLock; // protect mInflightFrames |
| 354 | std::unordered_set<uint32_t> mInflightFrames; |
| 355 | |
| 356 | // Stream ID -> circulating buffers map |
| 357 | std::map<int, CirculatingBuffers> mCirculatingBuffers; |
| 358 | // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock |
| 359 | mutable Mutex mCbsLock; |
| 360 | |
| 361 | std::mutex mAfTriggerLock; // protect mAfTrigger |
| 362 | bool mAfTrigger = false; |
| 363 | |
| 364 | uint32_t mBlobBufferSize = 0; |
| 365 | |
| 366 | static HandleImporter sHandleImporter; |
| 367 | |
Avichal Rakesh | e1857f8 | 2022-06-08 17:47:23 -0700 | [diff] [blame] | 368 | std::shared_ptr<BufferRequestThread> mBufferRequestThread; |
| 369 | |
| 370 | /* Beginning of members not changed after initialize() */ |
| 371 | using RequestMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>; |
| 372 | std::unique_ptr<RequestMetadataQueue> mRequestMetadataQueue; |
| 373 | using ResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>; |
| 374 | std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue; |
| 375 | |
| 376 | // Protect against invokeProcessCaptureResultCallback() |
| 377 | Mutex mProcessCaptureResultLock; |
| 378 | |
| 379 | // tracks last seen stream config counter |
| 380 | int32_t mLastStreamConfigCounter = -1; |
| 381 | |
| 382 | std::unordered_map<RequestTemplate, CameraMetadata> mDefaultRequests; |
| 383 | |
| 384 | const Size mMaxThumbResolution; |
| 385 | const Size mMaxJpegResolution; |
| 386 | |
| 387 | std::string mExifMake; |
| 388 | std::string mExifModel; |
| 389 | /* End of members not changed after initialize() */ |
| 390 | }; |
| 391 | |
| 392 | } // namespace implementation |
| 393 | } // namespace device |
| 394 | } // namespace camera |
| 395 | } // namespace hardware |
| 396 | } // namespace android |
| 397 | |
| 398 | #endif // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICESESSION_H_ |