From 190e5601d6efdac6134fdf626001590015a4a255 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Tue, 13 Feb 2018 17:43:13 -0800 Subject: [PATCH] Camera: implement external camera flush Test: CTS abort capture test Bug: 72261676 Change-Id: I0c3af8693a885672953ff394121c40c5ade59964 --- .../default/ExternalCameraDeviceSession.cpp | 100 +++++++++++------- .../ExternalCameraDeviceSession.h | 18 +++- 2 files changed, 72 insertions(+), 46 deletions(-) diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp index 5de1442b72..b6b46263c8 100644 --- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp +++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp @@ -281,6 +281,12 @@ Return ExternalCameraDeviceSession::processCaptureRequest_3_4( } Return ExternalCameraDeviceSession::flush() { + Mutex::Autolock _il(mInterfaceLock); + Status status = initStatus(); + if (status != Status::OK) { + return status; + } + mOutputThread->flush(); return Status::OK; } @@ -492,7 +498,7 @@ void ExternalCameraDeviceSession::notifyError( } //TODO: refactor with processCaptureResult -Status ExternalCameraDeviceSession::processCaptureRequestError(HalRequest& req) { +Status ExternalCameraDeviceSession::processCaptureRequestError(const HalRequest& req) { // Return V4L2 buffer to V4L2 buffer queue enqueueV4l2Frame(req.frameIn); @@ -1494,19 +1500,23 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { return true; } + auto onDeviceError = [&](auto... args) { + ALOGE(args...); + parent->notifyError( + req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); + signalRequestDone(); + return false; + }; + if (req.frameIn->mFourcc != V4L2_PIX_FMT_MJPEG) { - ALOGE("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__, + return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__, req.frameIn->mFourcc & 0xFF, (req.frameIn->mFourcc >> 8) & 0xFF, (req.frameIn->mFourcc >> 16) & 0xFF, (req.frameIn->mFourcc >> 24) & 0xFF); - parent->notifyError( - /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); - return false; } - std::unique_lock lk(mLock); - + std::unique_lock lk(mBufferLock); // Convert input V4L2 frame to YU12 of the same size // TODO: see if we can save some computation by converting to YV12 here uint8_t* inData; @@ -1531,11 +1541,9 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { lk.unlock(); Status st = parent->processCaptureRequestError(req); if (st != Status::OK) { - ALOGE("%s: failed to process capture request error!", __FUNCTION__); - parent->notifyError( - /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); - return false; + return onDeviceError("%s: failed to process capture request error!", __FUNCTION__); } + signalRequestDone(); return true; } @@ -1562,15 +1570,9 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { int ret = createJpegLocked(halBuf, req); if(ret != 0) { - ALOGE("%s: createJpegLocked failed with %d", - __FUNCTION__, ret); lk.unlock(); - parent->notifyError( - /*frameNum*/req.frameNumber, - /*stream*/-1, - ErrorCode::ERROR_DEVICE); - - return false; + return onDeviceError("%s: createJpegLocked failed with %d", + __FUNCTION__, ret); } } break; case PixelFormat::YCBCR_420_888: @@ -1598,21 +1600,15 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { Size { halBuf.width, halBuf.height }, &cropAndScaled); if (ret != 0) { - ALOGE("%s: crop and scale failed!", __FUNCTION__); lk.unlock(); - parent->notifyError( - /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); - return false; + return onDeviceError("%s: crop and scale failed!", __FUNCTION__); } Size sz {halBuf.width, halBuf.height}; ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc); if (ret != 0) { - ALOGE("%s: format coversion failed!", __FUNCTION__); lk.unlock(); - parent->notifyError( - /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); - return false; + return onDeviceError("%s: format coversion failed!", __FUNCTION__); } int relFence = sHandleImporter.unlock(*(halBuf.bufPtr)); if (relFence > 0) { @@ -1620,11 +1616,8 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { } } break; default: - ALOGE("%s: unknown output format %x", __FUNCTION__, halBuf.format); lk.unlock(); - parent->notifyError( - /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); - return false; + return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format); } } // for each buffer mScaledYu12Frames.clear(); @@ -1633,18 +1626,16 @@ bool ExternalCameraDeviceSession::OutputThread::threadLoop() { lk.unlock(); Status st = parent->processCaptureResult(req); if (st != Status::OK) { - ALOGE("%s: failed to process capture result!", __FUNCTION__); - parent->notifyError( - /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE); - return false; + return onDeviceError("%s: failed to process capture result!", __FUNCTION__); } + signalRequestDone(); return true; } Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers( const Size& v4lSize, const Size& thumbSize, const hidl_vec& streams) { - std::lock_guard lk(mLock); + std::lock_guard lk(mBufferLock); if (mScaledYu12Frames.size() != 0) { ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)", __FUNCTION__, mScaledYu12Frames.size()); @@ -1716,17 +1707,36 @@ Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers( } Status ExternalCameraDeviceSession::OutputThread::submitRequest(const HalRequest& req) { - std::lock_guard lk(mLock); + std::unique_lock lk(mRequestListLock); // TODO: reduce object copy in this path mRequestList.push_back(req); + lk.unlock(); mRequestCond.notify_one(); return Status::OK; } void ExternalCameraDeviceSession::OutputThread::flush() { - std::lock_guard lk(mLock); - // TODO: send buffer/request errors back to framework + auto parent = mParent.promote(); + if (parent == nullptr) { + ALOGE("%s: session has been disconnected!", __FUNCTION__); + return; + } + + std::unique_lock lk(mRequestListLock); + std::list reqs = mRequestList; mRequestList.clear(); + if (mProcessingRequest) { + std::chrono::seconds timeout = std::chrono::seconds(kReqWaitTimeoutSec); + auto st = mRequestDoneCond.wait_for(lk, timeout); + if (st == std::cv_status::timeout) { + ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__); + } + } + + lk.unlock(); + for (const auto& req : reqs) { + parent->processCaptureRequestError(req); + } } void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(HalRequest* out) { @@ -1735,7 +1745,7 @@ void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(HalRequest* o return; } - std::unique_lock lk(mLock); + std::unique_lock lk(mRequestListLock); while (mRequestList.empty()) { std::chrono::seconds timeout = std::chrono::seconds(kReqWaitTimeoutSec); auto st = mRequestCond.wait_for(lk, timeout); @@ -1746,6 +1756,14 @@ void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(HalRequest* o } *out = mRequestList.front(); mRequestList.pop_front(); + mProcessingRequest = true; +} + +void ExternalCameraDeviceSession::OutputThread::signalRequestDone() { + std::unique_lock lk(mRequestListLock); + mProcessingRequest = false; + lk.unlock(); + mRequestDoneCond.notify_one(); } void ExternalCameraDeviceSession::cleanupBuffersLocked(int id) { @@ -2068,8 +2086,8 @@ void ExternalCameraDeviceSession::enqueueV4l2Frame(const sp& frame) { { std::lock_guard lk(mV4l2BufferLock); mNumDequeuedV4l2Buffers--; - mV4L2BufferReturned.notify_one(); } + mV4L2BufferReturned.notify_one(); } Status ExternalCameraDeviceSession::configureStreams( diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h index cced3f7628..62b6c273aa 100644 --- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h +++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h @@ -203,7 +203,7 @@ protected: Status processOneCaptureRequest(const CaptureRequest& request); Status processCaptureResult(HalRequest&); - Status processCaptureRequestError(HalRequest&); + Status processCaptureRequestError(const HalRequest&); void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs); void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec); void invokeProcessCaptureResultCallback( @@ -239,6 +239,8 @@ protected: static const int kReqWaitTimeoutSec = 3; void waitForNextRequest(HalRequest* out); + void signalRequestDone(); + int cropAndScaleLocked( sp& in, const Size& outSize, YCbCrLayout* out); @@ -258,15 +260,20 @@ protected: int createJpegLocked(HalStreamBuffer &halBuf, HalRequest &req); - mutable std::mutex mLock; - std::condition_variable mRequestCond; - wp mParent; - CroppingType mCroppingType; + const wp mParent; + const CroppingType mCroppingType; + + mutable std::mutex mRequestListLock; // Protect acccess to mRequestList + std::condition_variable mRequestCond; // signaled when a new request is submitted + std::condition_variable mRequestDoneCond; // signaled when a request is done processing std::list mRequestList; + bool mProcessingRequest = false; + // V4L2 frameIn // (MJPG decode)-> mYu12Frame // (Scale)-> mScaledYu12Frames // (Format convert) -> output gralloc frames + mutable std::mutex mBufferLock; // Protect access to intermediate buffers sp mYu12Frame; sp mYu12ThumbFrame; std::unordered_map, SizeHasher> mIntermediateBuffers; @@ -303,6 +310,7 @@ protected: std::condition_variable mV4L2BufferReturned; size_t mNumDequeuedV4l2Buffers = 0; + // Not protected by mLock (but might be used when mLock is locked) sp mOutputThread; // Stream ID -> Camera3Stream cache