blob: 0cc81bbe9e9dbb0fa80005bb79fbeedb1776779e [file] [log] [blame]
Yin-Chia Yeh4da7c6c2020-01-16 17:06:36 -08001/*
2 * Copyright (C) 2020 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#define LOG_TAG "ExtCamDevSsn@3.6"
18#include <android/log.h>
19
20#include <utils/Trace.h>
21#include "ExternalCameraDeviceSession.h"
22
23namespace android {
24namespace hardware {
25namespace camera {
26namespace device {
27namespace V3_6 {
28namespace implementation {
29
30ExternalCameraDeviceSession::ExternalCameraDeviceSession(
31 const sp<V3_2::ICameraDeviceCallback>& callback,
32 const ExternalCameraConfig& cfg,
33 const std::vector<SupportedV4L2Format>& sortedFormats,
34 const CroppingType& croppingType,
35 const common::V1_0::helper::CameraMetadata& chars,
36 const std::string& cameraId,
37 unique_fd v4l2Fd) :
38 V3_5::implementation::ExternalCameraDeviceSession(
39 callback, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd)) {
40}
41
42ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {}
43
44
45Return<void> ExternalCameraDeviceSession::configureStreams_3_6(
46 const StreamConfiguration& requestedConfiguration,
47 ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb) {
48 V3_2::StreamConfiguration config_v32;
49 V3_3::HalStreamConfiguration outStreams_v33;
50 V3_6::HalStreamConfiguration outStreams;
51 const V3_4::StreamConfiguration& requestedConfiguration_3_4 = requestedConfiguration.v3_4;
52 Mutex::Autolock _il(mInterfaceLock);
53
54 config_v32.operationMode = requestedConfiguration_3_4.operationMode;
55 config_v32.streams.resize(requestedConfiguration_3_4.streams.size());
56 uint32_t blobBufferSize = 0;
57 int numStallStream = 0;
58 for (size_t i = 0; i < config_v32.streams.size(); i++) {
59 config_v32.streams[i] = requestedConfiguration_3_4.streams[i].v3_2;
60 if (config_v32.streams[i].format == PixelFormat::BLOB) {
61 blobBufferSize = requestedConfiguration_3_4.streams[i].bufferSize;
62 numStallStream++;
63 }
64 }
65
66 // Fail early if there are multiple BLOB streams
67 if (numStallStream > kMaxStallStream) {
68 ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__,
69 kMaxStallStream, numStallStream);
70 _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams);
71 return Void();
72 }
73
74 Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize);
75
Yin-Chia Yeh5dab7282020-01-21 10:08:12 -080076 fillOutputStream3_6(outStreams_v33, &outStreams);
77
Yin-Chia Yeh4da7c6c2020-01-16 17:06:36 -080078 _hidl_cb(status, outStreams);
79 return Void();
80}
81
82Return<void> ExternalCameraDeviceSession::switchToOffline(
83 const hidl_vec<int32_t>& streamsToKeep,
84 ICameraDeviceSession::switchToOffline_cb _hidl_cb) {
Yin-Chia Yeh5dab7282020-01-21 10:08:12 -080085 std::vector<NotifyMsg> msgs;
86 std::vector<CaptureResult> results;
87 CameraOfflineSessionInfo info;
88 sp<ICameraOfflineSession> session;
89
90 Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session);
91
92 mCallback->notify(msgs);
93 hidl_vec<CaptureResult> hidlResults(std::move(results));
94 invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true);
95 V3_4::implementation::freeReleaseFences(hidlResults);
96
97 _hidl_cb(st, info, session);
Yin-Chia Yeh4da7c6c2020-01-16 17:06:36 -080098 return Void();
99}
100
Yin-Chia Yeh5dab7282020-01-21 10:08:12 -0800101void ExternalCameraDeviceSession::fillOutputStream3_6(
102 const V3_3::HalStreamConfiguration& outStreams_v33,
103 /*out*/V3_6::HalStreamConfiguration* outStreams_v36) {
104 if (outStreams_v36 == nullptr) {
105 ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__);
106 return;
107 }
108 Mutex::Autolock _l(mLock);
109 outStreams_v36->streams.resize(outStreams_v33.streams.size());
110 for (size_t i = 0; i < outStreams_v36->streams.size(); i++) {
111 outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i];
112 outStreams_v36->streams[i].supportOffline =
113 supportOfflineLocked(outStreams_v33.streams[i].v3_2.id);
114 }
115}
116
117bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
118 const Stream& stream = mStreamMap[streamId];
119 if (stream.format == PixelFormat::BLOB &&
120 stream.dataSpace == static_cast<int32_t>(Dataspace::V0_JFIF)) {
121 return true;
122 }
123 // TODO: support YUV output stream?
124 return false;
125}
126
127bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec<int32_t>& offlineStreams,
128 std::shared_ptr<V3_4::implementation::HalRequest> halReq) {
129 for (const auto& buffer : halReq->buffers) {
130 for (auto offlineStreamId : offlineStreams) {
131 if (buffer.streamId == offlineStreamId) {
132 return false;
133 }
134 }
135 }
136 // Only drop a request completely if it has no offline output
137 return true;
138}
139
140void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
141 std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
142 const std::map<int, CirculatingBuffers>& circulatingBuffers,
143 /*out*/CameraOfflineSessionInfo* info) {
144 if (info == nullptr) {
145 ALOGE("%s: output info must not be null!", __FUNCTION__);
146 return;
147 }
148
149 info->offlineStreams.resize(offlineStreams.size());
150 info->offlineRequests.resize(offlineReqs.size());
151
152 std::unordered_map<int32_t, uint32_t> outstandingBufs(offlineStreams.size());
153 for (const auto streamId : offlineStreams) {
154 outstandingBufs.insert({streamId, 0});
155 }
156 // Fill in offline reqs and count outstanding buffers
157 for (size_t i = 0; i < offlineReqs.size(); i++) {
158 info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
159 info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
160 for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
161 int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
162 info->offlineRequests[i].pendingStreams[bIdx] = streamId;
163 outstandingBufs[streamId]++;
164 }
165 }
166
167 for (size_t i = 0; i < offlineStreams.size(); i++) {
168 int32_t streamId = offlineStreams[i];
169 info->offlineStreams[i].id = streamId;
170 info->offlineStreams[i].numOutstandingBuffers = outstandingBufs[streamId];
171 const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
172 info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
173 size_t bIdx = 0;
174 for (const auto& pair : bufIdMap) {
175 // Fill in bufferId
176 info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
177 }
178
179 }
180}
181
182Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec<int32_t>& offlineStreams,
183 /*out*/std::vector<NotifyMsg>* msgs,
184 /*out*/std::vector<CaptureResult>* results,
185 /*out*/CameraOfflineSessionInfo* info,
186 /*out*/sp<ICameraOfflineSession>* session) {
187 ATRACE_CALL();
188 if (offlineStreams.size() > 1) {
189 ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
190 return Status::ILLEGAL_ARGUMENT;
191 }
192
193 if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
194 ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__,
195 msgs, results, info, session);
196 return Status::ILLEGAL_ARGUMENT;
197 }
198
199 msgs->clear();
200 results->clear();
201
202 Mutex::Autolock _il(mInterfaceLock);
203 Status status = initStatus();
204 if (status != Status::OK) {
205 return status;
206 }
207
208 Mutex::Autolock _l(mLock);
209 for (auto streamId : offlineStreams) {
210 if (!supportOfflineLocked(streamId)) {
211 return Status::ILLEGAL_ARGUMENT;
212 }
213 }
214
215 // pause output thread and get all remaining inflight requests
216 auto remainingReqs = mOutputThread->switchToOffline();
217 std::vector<std::shared_ptr<V3_4::implementation::HalRequest>> halReqs;
218
219 // Send out buffer/request error for remaining requests and filter requests
220 // to be handled in offline mode
221 for (auto& halReq : remainingReqs) {
222 bool dropReq = canDropRequest(offlineStreams, halReq);
223 if (dropReq) {
224 // Request is dropped completely. Just send request error and
225 // there is no need to send the request to offline session
226 processCaptureRequestError(halReq, msgs, results);
227 continue;
228 }
229
230 // All requests reach here must have at least one offline stream output
231 NotifyMsg shutter;
232 shutter.type = MsgType::SHUTTER;
233 shutter.msg.shutter.frameNumber = halReq->frameNumber;
234 shutter.msg.shutter.timestamp = halReq->shutterTs;
235 msgs->push_back(shutter);
236
237 std::vector<V3_4::implementation::HalStreamBuffer> offlineBuffers;
238 for (const auto& buffer : halReq->buffers) {
239 bool dropBuffer = true;
240 for (auto offlineStreamId : offlineStreams) {
241 if (buffer.streamId == offlineStreamId) {
242 dropBuffer = false;
243 break;
244 }
245 }
246 if (dropBuffer) {
247 NotifyMsg error;
248 error.type = MsgType::ERROR;
249 error.msg.error.frameNumber = halReq->frameNumber;
250 error.msg.error.errorStreamId = buffer.streamId;
251 error.msg.error.errorCode = ErrorCode::ERROR_BUFFER;
252 msgs->push_back(error);
253
254 CaptureResult result;
255 result.frameNumber = halReq->frameNumber;
256 result.partialResult = 0; // buffer only result
257 result.inputBuffer.streamId = -1;
258 result.outputBuffers.resize(1);
259 result.outputBuffers[0].streamId = buffer.streamId;
260 result.outputBuffers[0].bufferId = buffer.bufferId;
261 result.outputBuffers[0].status = BufferStatus::ERROR;
262 if (buffer.acquireFence >= 0) {
263 native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
264 handle->data[0] = buffer.acquireFence;
265 result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false);
266 }
267 results->push_back(result);
268 } else {
269 offlineBuffers.push_back(buffer);
270 }
271 }
272 halReq->buffers = offlineBuffers;
273 halReqs.push_back(halReq);
274 }
275
276 // convert hal requests to offline request
277 std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
278 for (auto& v4lReq : halReqs) {
279 std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
280 halReq->frameNumber = v4lReq->frameNumber;
281 halReq->setting = v4lReq->setting;
282 halReq->shutterTs = v4lReq->shutterTs;
283 halReq->buffers = v4lReq->buffers;
284 sp<V3_4::implementation::V4L2Frame> v4l2Frame =
285 static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
286 halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame);
287 offlineReqs.push_back(halReq);
288 // enqueue V4L2 frame
289 enqueueV4l2Frame(v4l2Frame);
290 }
291
292 // Collect buffer caches/streams
293 hidl_vec<Stream> streamInfos;
294 streamInfos.resize(offlineStreams.size());
295 std::map<int, CirculatingBuffers> circulatingBuffers;
296 {
297 Mutex::Autolock _l(mCbsLock);
298 size_t idx = 0;
299 for(auto streamId : offlineStreams) {
300 circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
301 mCirculatingBuffers.erase(streamId);
302 streamInfos[idx++] = mStreamMap.at(streamId);
303 mStreamMap.erase(streamId);
304 }
305 }
306
307 fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
308
309 // create the offline session object
310 bool afTrigger;
311 {
312 std::lock_guard<std::mutex> lk(mAfTriggerLock);
313 afTrigger = mAfTrigger;
314 }
315 sp<ExternalCameraOfflineSession> sessionImpl = new ExternalCameraOfflineSession(
316 mCroppingType, mCameraCharacteristics, mCameraId,
317 mExifMake, mExifModel, mBlobBufferSize, afTrigger,
318 streamInfos, offlineReqs, circulatingBuffers);
319
320 bool initFailed = sessionImpl->initialize();
321 if (initFailed) {
322 ALOGE("%s: offline session initialize failed!", __FUNCTION__);
323 return Status::INTERNAL_ERROR;
324 }
325
326 // cleanup stream and buffer caches
327 {
328 Mutex::Autolock _l(mCbsLock);
329 for(auto pair : mStreamMap) {
330 cleanupBuffersLocked(/*Stream ID*/pair.first);
331 }
332 mCirculatingBuffers.clear();
333 }
334 mStreamMap.clear();
335
336 // update inflight records
337 {
338 std::lock_guard<std::mutex> lk(mInflightFramesLock);
339 mInflightFrames.clear();
340 }
341
342 // stop v4l2 streaming
343 if (v4l2StreamOffLocked() !=0) {
344 ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
345 return Status::INTERNAL_ERROR;
346 }
347
348 *session = sessionImpl->getInterface();
349 return Status::OK;
350}
351
Yin-Chia Yeh4da7c6c2020-01-16 17:06:36 -0800352} // namespace implementation
353} // namespace V3_6
354} // namespace device
355} // namespace camera
356} // namespace hardware
357} // namespace android