Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 190e5601 authored by Yin-Chia Yeh's avatar Yin-Chia Yeh
Browse files

Camera: implement external camera flush

Test: CTS abort capture test
Bug: 72261676
Change-Id: I0c3af8693a885672953ff394121c40c5ade59964
parent 134093a4
Loading
Loading
Loading
Loading
+59 −41
Original line number Diff line number Diff line
@@ -281,6 +281,12 @@ Return<void> ExternalCameraDeviceSession::processCaptureRequest_3_4(
}

Return<Status> 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<std::mutex> lk(mLock);

    std::unique_lock<std::mutex> 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<Stream>& streams) {
    std::lock_guard<std::mutex> lk(mLock);
    std::lock_guard<std::mutex> 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<std::mutex> lk(mLock);
    std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> lk(mRequestListLock);
    std::list<HalRequest> 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<std::mutex> lk(mLock);
    std::unique_lock<std::mutex> 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<std::mutex> lk(mRequestListLock);
    mProcessingRequest = false;
    lk.unlock();
    mRequestDoneCond.notify_one();
}

void ExternalCameraDeviceSession::cleanupBuffersLocked(int id) {
@@ -2068,8 +2086,8 @@ void ExternalCameraDeviceSession::enqueueV4l2Frame(const sp<V4L2Frame>& frame) {
    {
        std::lock_guard<std::mutex> lk(mV4l2BufferLock);
        mNumDequeuedV4l2Buffers--;
        mV4L2BufferReturned.notify_one();
    }
    mV4L2BufferReturned.notify_one();
}

Status ExternalCameraDeviceSession::configureStreams(
+13 −5
Original line number Diff line number Diff line
@@ -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<AllocatedFrame>& 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<ExternalCameraDeviceSession> mParent;
        CroppingType mCroppingType;
        const wp<ExternalCameraDeviceSession> 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<HalRequest> 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<AllocatedFrame> mYu12Frame;
        sp<AllocatedFrame> mYu12ThumbFrame;
        std::unordered_map<Size, sp<AllocatedFrame>, 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<OutputThread> mOutputThread;

    // Stream ID -> Camera3Stream cache