Camera: implement external camera flush
Test: CTS abort capture test
Bug: 72261676
Change-Id: I0c3af8693a885672953ff394121c40c5ade59964
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 5de1442..b6b4626 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -281,6 +281,12 @@
}
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 @@
}
//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 @@
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 @@
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 @@
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 @@
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 @@
}
} 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 @@
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::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 @@
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 @@
}
*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 @@
{
std::lock_guard<std::mutex> lk(mV4l2BufferLock);
mNumDequeuedV4l2Buffers--;
- mV4L2BufferReturned.notify_one();
}
+ mV4L2BufferReturned.notify_one();
}
Status ExternalCameraDeviceSession::configureStreams(