Camera: implement external camera flush
Test: CTS abort capture test Bug: 72261676 Change-Id: I0c3af8693a885672953ff394121c40c5ade59964
This commit is contained in:
parent
134093a43f
commit
190e5601d6
2 changed files with 72 additions and 46 deletions
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue