1 /*
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 
23 namespace android {
24 namespace hardware {
25 namespace camera {
26 namespace device {
27 namespace V3_6 {
28 namespace implementation {
29 
ExternalCameraDeviceSession(const sp<V3_2::ICameraDeviceCallback> & callback,const ExternalCameraConfig & cfg,const std::vector<SupportedV4L2Format> & sortedFormats,const CroppingType & croppingType,const common::V1_0::helper::CameraMetadata & chars,const std::string & cameraId,unique_fd v4l2Fd)30 ExternalCameraDeviceSession::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 
~ExternalCameraDeviceSession()42 ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {}
43 
44 
configureStreams_3_6(const StreamConfiguration & requestedConfiguration,ICameraDeviceSession::configureStreams_3_6_cb _hidl_cb)45 Return<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 
76     fillOutputStream3_6(outStreams_v33, &outStreams);
77 
78     _hidl_cb(status, outStreams);
79     return Void();
80 }
81 
switchToOffline(const hidl_vec<int32_t> & streamsToKeep,ICameraDeviceSession::switchToOffline_cb _hidl_cb)82 Return<void> ExternalCameraDeviceSession::switchToOffline(
83         const hidl_vec<int32_t>& streamsToKeep,
84         ICameraDeviceSession::switchToOffline_cb _hidl_cb) {
85     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);
98     return Void();
99 }
100 
fillOutputStream3_6(const V3_3::HalStreamConfiguration & outStreams_v33,V3_6::HalStreamConfiguration * outStreams_v36)101 void 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 
supportOfflineLocked(int32_t streamId)117 bool 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 
canDropRequest(const hidl_vec<int32_t> & offlineStreams,std::shared_ptr<V3_4::implementation::HalRequest> halReq)127 bool 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 
fillOfflineSessionInfo(const hidl_vec<int32_t> & offlineStreams,std::deque<std::shared_ptr<HalRequest>> & offlineReqs,const std::map<int,CirculatingBuffers> & circulatingBuffers,CameraOfflineSessionInfo * info)140 void 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     // Fill in offline reqs and count outstanding buffers
153     for (size_t i = 0; i < offlineReqs.size(); i++) {
154         info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
155         info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
156         for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
157             int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
158             info->offlineRequests[i].pendingStreams[bIdx] = streamId;
159         }
160     }
161 
162     for (size_t i = 0; i < offlineStreams.size(); i++) {
163         int32_t streamId = offlineStreams[i];
164         info->offlineStreams[i].id = streamId;
165         // outstanding buffers are 0 since we are doing hal buffer management and
166         // offline session will ask for those buffers later
167         info->offlineStreams[i].numOutstandingBuffers = 0;
168         const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
169         info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
170         size_t bIdx = 0;
171         for (const auto& pair : bufIdMap) {
172             // Fill in bufferId
173             info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
174         }
175 
176     }
177 }
178 
switchToOffline(const hidl_vec<int32_t> & offlineStreams,std::vector<NotifyMsg> * msgs,std::vector<CaptureResult> * results,CameraOfflineSessionInfo * info,sp<ICameraOfflineSession> * session)179 Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec<int32_t>& offlineStreams,
180         /*out*/std::vector<NotifyMsg>* msgs,
181         /*out*/std::vector<CaptureResult>* results,
182         /*out*/CameraOfflineSessionInfo* info,
183         /*out*/sp<ICameraOfflineSession>* session) {
184     ATRACE_CALL();
185     if (offlineStreams.size() > 1) {
186         ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
187         return Status::ILLEGAL_ARGUMENT;
188     }
189 
190     if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
191         ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__,
192                 msgs, results, info, session);
193         return Status::ILLEGAL_ARGUMENT;
194     }
195 
196     msgs->clear();
197     results->clear();
198 
199     Mutex::Autolock _il(mInterfaceLock);
200     Status status = initStatus();
201     if (status != Status::OK) {
202         return status;
203     }
204 
205     Mutex::Autolock _l(mLock);
206     for (auto streamId : offlineStreams) {
207         if (!supportOfflineLocked(streamId)) {
208             return Status::ILLEGAL_ARGUMENT;
209         }
210     }
211 
212     // pause output thread and get all remaining inflight requests
213     auto remainingReqs = mOutputThread->switchToOffline();
214     std::vector<std::shared_ptr<V3_4::implementation::HalRequest>> halReqs;
215 
216     // Send out buffer/request error for remaining requests and filter requests
217     // to be handled in offline mode
218     for (auto& halReq : remainingReqs) {
219         bool dropReq = canDropRequest(offlineStreams, halReq);
220         if (dropReq) {
221             // Request is dropped completely. Just send request error and
222             // there is no need to send the request to offline session
223             processCaptureRequestError(halReq, msgs, results);
224             continue;
225         }
226 
227         // All requests reach here must have at least one offline stream output
228         NotifyMsg shutter;
229         shutter.type = MsgType::SHUTTER;
230         shutter.msg.shutter.frameNumber = halReq->frameNumber;
231         shutter.msg.shutter.timestamp = halReq->shutterTs;
232         msgs->push_back(shutter);
233 
234         std::vector<V3_4::implementation::HalStreamBuffer> offlineBuffers;
235         for (const auto& buffer : halReq->buffers) {
236             bool dropBuffer = true;
237             for (auto offlineStreamId : offlineStreams) {
238                 if (buffer.streamId == offlineStreamId) {
239                     dropBuffer = false;
240                     break;
241                 }
242             }
243             if (dropBuffer) {
244                 NotifyMsg error;
245                 error.type = MsgType::ERROR;
246                 error.msg.error.frameNumber = halReq->frameNumber;
247                 error.msg.error.errorStreamId = buffer.streamId;
248                 error.msg.error.errorCode = ErrorCode::ERROR_BUFFER;
249                 msgs->push_back(error);
250 
251                 CaptureResult result;
252                 result.frameNumber = halReq->frameNumber;
253                 result.partialResult = 0; // buffer only result
254                 result.inputBuffer.streamId = -1;
255                 result.outputBuffers.resize(1);
256                 result.outputBuffers[0].streamId = buffer.streamId;
257                 result.outputBuffers[0].bufferId = buffer.bufferId;
258                 result.outputBuffers[0].status = BufferStatus::ERROR;
259                 if (buffer.acquireFence >= 0) {
260                     native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
261                     handle->data[0] = buffer.acquireFence;
262                     result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false);
263                 }
264                 results->push_back(result);
265             } else {
266                 offlineBuffers.push_back(buffer);
267             }
268         }
269         halReq->buffers = offlineBuffers;
270         halReqs.push_back(halReq);
271     }
272 
273     // convert hal requests to offline request
274     std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
275     size_t i = 0;
276     for (auto& v4lReq : halReqs) {
277         offlineReqs[i] = std::make_shared<HalRequest>();
278         offlineReqs[i]->frameNumber = v4lReq->frameNumber;
279         offlineReqs[i]->setting = v4lReq->setting;
280         offlineReqs[i]->shutterTs = v4lReq->shutterTs;
281         offlineReqs[i]->buffers = v4lReq->buffers;
282         sp<V3_4::implementation::V4L2Frame> v4l2Frame =
283                 static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
284         offlineReqs[i]->frameIn = new AllocatedV4L2Frame(v4l2Frame);
285         i++;
286         // enqueue V4L2 frame
287         enqueueV4l2Frame(v4l2Frame);
288     }
289 
290     // Collect buffer caches/streams
291     hidl_vec<Stream> streamInfos;
292     streamInfos.resize(offlineStreams.size());
293     std::map<int, CirculatingBuffers> circulatingBuffers;
294     {
295         Mutex::Autolock _l(mCbsLock);
296         size_t idx = 0;
297         for(auto streamId : offlineStreams) {
298             circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
299             mCirculatingBuffers.erase(streamId);
300             streamInfos[idx++] = mStreamMap.at(streamId);
301             mStreamMap.erase(streamId);
302         }
303     }
304 
305     fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
306 
307     // create the offline session object
308     bool afTrigger;
309     {
310         std::lock_guard<std::mutex> lk(mAfTriggerLock);
311         afTrigger = mAfTrigger;
312     }
313     sp<ExternalCameraOfflineSession> sessionImpl = new ExternalCameraOfflineSession(
314             mCroppingType, mCameraCharacteristics, mCameraId,
315             mExifMake, mExifModel, mBlobBufferSize, afTrigger,
316             streamInfos, offlineReqs, circulatingBuffers);
317 
318     bool initFailed = sessionImpl->initialize();
319     if (initFailed) {
320         ALOGE("%s: offline session initialize failed!", __FUNCTION__);
321         return Status::INTERNAL_ERROR;
322     }
323 
324     // cleanup stream and buffer caches
325     {
326         Mutex::Autolock _l(mCbsLock);
327         for(auto pair : mStreamMap) {
328             cleanupBuffersLocked(/*Stream ID*/pair.first);
329         }
330         mCirculatingBuffers.clear();
331     }
332     mStreamMap.clear();
333 
334     // update inflight records
335     {
336         std::lock_guard<std::mutex> lk(mInflightFramesLock);
337         mInflightFrames.clear();
338     }
339 
340     // stop v4l2 streaming
341     if (v4l2StreamOffLocked() !=0) {
342         ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
343         return Status::INTERNAL_ERROR;
344     }
345 
346     // No need to return session if there is no offline requests left
347     if (offlineReqs.size() != 0) {
348         *session = sessionImpl->getInterface();
349     } else {
350         *session = nullptr;
351     }
352     return Status::OK;
353 }
354 
355 } // namespace implementation
356 }  // namespace V3_6
357 }  // namespace device
358 }  // namespace camera
359 }  // namespace hardware
360 }  // namespace android
361