xref: /aosp_15_r20/hardware/interfaces/automotive/evs/1.0/default/EvsCamera.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "[email protected]"
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include "EvsCamera.h"
20*4d7e907cSAndroid Build Coastguard Worker #include "EvsEnumerator.h"
21*4d7e907cSAndroid Build Coastguard Worker 
22*4d7e907cSAndroid Build Coastguard Worker #include <ui/GraphicBufferAllocator.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <ui/GraphicBufferMapper.h>
24*4d7e907cSAndroid Build Coastguard Worker 
25*4d7e907cSAndroid Build Coastguard Worker 
26*4d7e907cSAndroid Build Coastguard Worker namespace android {
27*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
28*4d7e907cSAndroid Build Coastguard Worker namespace automotive {
29*4d7e907cSAndroid Build Coastguard Worker namespace evs {
30*4d7e907cSAndroid Build Coastguard Worker namespace V1_0 {
31*4d7e907cSAndroid Build Coastguard Worker namespace implementation {
32*4d7e907cSAndroid Build Coastguard Worker 
33*4d7e907cSAndroid Build Coastguard Worker 
34*4d7e907cSAndroid Build Coastguard Worker // Special camera names for which we'll initialize alternate test data
35*4d7e907cSAndroid Build Coastguard Worker const char EvsCamera::kCameraName_Backup[]    = "backup";
36*4d7e907cSAndroid Build Coastguard Worker 
37*4d7e907cSAndroid Build Coastguard Worker 
38*4d7e907cSAndroid Build Coastguard Worker // Arbitrary limit on number of graphics buffers allowed to be allocated
39*4d7e907cSAndroid Build Coastguard Worker // Safeguards against unreasonable resource consumption and provides a testable limit
40*4d7e907cSAndroid Build Coastguard Worker const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
41*4d7e907cSAndroid Build Coastguard Worker 
42*4d7e907cSAndroid Build Coastguard Worker 
EvsCamera(const char * id)43*4d7e907cSAndroid Build Coastguard Worker EvsCamera::EvsCamera(const char *id) :
44*4d7e907cSAndroid Build Coastguard Worker         mFramesAllowed(0),
45*4d7e907cSAndroid Build Coastguard Worker         mFramesInUse(0),
46*4d7e907cSAndroid Build Coastguard Worker         mStreamState(STOPPED) {
47*4d7e907cSAndroid Build Coastguard Worker 
48*4d7e907cSAndroid Build Coastguard Worker     ALOGD("EvsCamera instantiated");
49*4d7e907cSAndroid Build Coastguard Worker 
50*4d7e907cSAndroid Build Coastguard Worker     mDescription.cameraId = id;
51*4d7e907cSAndroid Build Coastguard Worker 
52*4d7e907cSAndroid Build Coastguard Worker     // Set up mock data for testing
53*4d7e907cSAndroid Build Coastguard Worker     if (mDescription.cameraId == kCameraName_Backup) {
54*4d7e907cSAndroid Build Coastguard Worker         mWidth  = 640;          // full NTSC/VGA
55*4d7e907cSAndroid Build Coastguard Worker         mHeight = 480;          // full NTSC/VGA
56*4d7e907cSAndroid Build Coastguard Worker         mDescription.vendorFlags = 0xFFFFFFFF;   // Arbitrary value
57*4d7e907cSAndroid Build Coastguard Worker     } else {
58*4d7e907cSAndroid Build Coastguard Worker         mWidth  = 320;          // 1/2 NTSC/VGA
59*4d7e907cSAndroid Build Coastguard Worker         mHeight = 240;          // 1/2 NTSC/VGA
60*4d7e907cSAndroid Build Coastguard Worker     }
61*4d7e907cSAndroid Build Coastguard Worker 
62*4d7e907cSAndroid Build Coastguard Worker     mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
63*4d7e907cSAndroid Build Coastguard Worker     mUsage  = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
64*4d7e907cSAndroid Build Coastguard Worker               GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
65*4d7e907cSAndroid Build Coastguard Worker }
66*4d7e907cSAndroid Build Coastguard Worker 
67*4d7e907cSAndroid Build Coastguard Worker 
~EvsCamera()68*4d7e907cSAndroid Build Coastguard Worker EvsCamera::~EvsCamera() {
69*4d7e907cSAndroid Build Coastguard Worker     ALOGD("EvsCamera being destroyed");
70*4d7e907cSAndroid Build Coastguard Worker     forceShutdown();
71*4d7e907cSAndroid Build Coastguard Worker }
72*4d7e907cSAndroid Build Coastguard Worker 
73*4d7e907cSAndroid Build Coastguard Worker 
74*4d7e907cSAndroid Build Coastguard Worker //
75*4d7e907cSAndroid Build Coastguard Worker // This gets called if another caller "steals" ownership of the camera
76*4d7e907cSAndroid Build Coastguard Worker //
forceShutdown()77*4d7e907cSAndroid Build Coastguard Worker void EvsCamera::forceShutdown()
78*4d7e907cSAndroid Build Coastguard Worker {
79*4d7e907cSAndroid Build Coastguard Worker     ALOGD("EvsCamera forceShutdown");
80*4d7e907cSAndroid Build Coastguard Worker 
81*4d7e907cSAndroid Build Coastguard Worker     // Make sure our output stream is cleaned up
82*4d7e907cSAndroid Build Coastguard Worker     // (It really should be already)
83*4d7e907cSAndroid Build Coastguard Worker     stopVideoStream();
84*4d7e907cSAndroid Build Coastguard Worker 
85*4d7e907cSAndroid Build Coastguard Worker     // Claim the lock while we work on internal state
86*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard <std::mutex> lock(mAccessLock);
87*4d7e907cSAndroid Build Coastguard Worker 
88*4d7e907cSAndroid Build Coastguard Worker     // Drop all the graphics buffers we've been using
89*4d7e907cSAndroid Build Coastguard Worker     if (mBuffers.size() > 0) {
90*4d7e907cSAndroid Build Coastguard Worker         GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
91*4d7e907cSAndroid Build Coastguard Worker         for (auto&& rec : mBuffers) {
92*4d7e907cSAndroid Build Coastguard Worker             if (rec.inUse) {
93*4d7e907cSAndroid Build Coastguard Worker                 ALOGE("Error - releasing buffer despite remote ownership");
94*4d7e907cSAndroid Build Coastguard Worker             }
95*4d7e907cSAndroid Build Coastguard Worker             alloc.free(rec.handle);
96*4d7e907cSAndroid Build Coastguard Worker             rec.handle = nullptr;
97*4d7e907cSAndroid Build Coastguard Worker         }
98*4d7e907cSAndroid Build Coastguard Worker         mBuffers.clear();
99*4d7e907cSAndroid Build Coastguard Worker     }
100*4d7e907cSAndroid Build Coastguard Worker 
101*4d7e907cSAndroid Build Coastguard Worker     // Put this object into an unrecoverable error state since somebody else
102*4d7e907cSAndroid Build Coastguard Worker     // is going to own the underlying camera now
103*4d7e907cSAndroid Build Coastguard Worker     mStreamState = DEAD;
104*4d7e907cSAndroid Build Coastguard Worker }
105*4d7e907cSAndroid Build Coastguard Worker 
106*4d7e907cSAndroid Build Coastguard Worker 
107*4d7e907cSAndroid Build Coastguard Worker // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
getCameraInfo(getCameraInfo_cb _hidl_cb)108*4d7e907cSAndroid Build Coastguard Worker Return<void> EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
109*4d7e907cSAndroid Build Coastguard Worker     ALOGD("getCameraInfo");
110*4d7e907cSAndroid Build Coastguard Worker 
111*4d7e907cSAndroid Build Coastguard Worker     // Send back our self description
112*4d7e907cSAndroid Build Coastguard Worker     _hidl_cb(mDescription);
113*4d7e907cSAndroid Build Coastguard Worker     return Void();
114*4d7e907cSAndroid Build Coastguard Worker }
115*4d7e907cSAndroid Build Coastguard Worker 
116*4d7e907cSAndroid Build Coastguard Worker 
setMaxFramesInFlight(uint32_t bufferCount)117*4d7e907cSAndroid Build Coastguard Worker Return<EvsResult> EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) {
118*4d7e907cSAndroid Build Coastguard Worker     ALOGD("setMaxFramesInFlight");
119*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mAccessLock);
120*4d7e907cSAndroid Build Coastguard Worker 
121*4d7e907cSAndroid Build Coastguard Worker     // If we've been displaced by another owner of the camera, then we can't do anything else
122*4d7e907cSAndroid Build Coastguard Worker     if (mStreamState == DEAD) {
123*4d7e907cSAndroid Build Coastguard Worker         ALOGE("ignoring setMaxFramesInFlight call when camera has been lost.");
124*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::OWNERSHIP_LOST;
125*4d7e907cSAndroid Build Coastguard Worker     }
126*4d7e907cSAndroid Build Coastguard Worker 
127*4d7e907cSAndroid Build Coastguard Worker     // We cannot function without at least one video buffer to send data
128*4d7e907cSAndroid Build Coastguard Worker     if (bufferCount < 1) {
129*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested");
130*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::INVALID_ARG;
131*4d7e907cSAndroid Build Coastguard Worker     }
132*4d7e907cSAndroid Build Coastguard Worker 
133*4d7e907cSAndroid Build Coastguard Worker     // Update our internal state
134*4d7e907cSAndroid Build Coastguard Worker     if (setAvailableFrames_Locked(bufferCount)) {
135*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::OK;
136*4d7e907cSAndroid Build Coastguard Worker     } else {
137*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::BUFFER_NOT_AVAILABLE;
138*4d7e907cSAndroid Build Coastguard Worker     }
139*4d7e907cSAndroid Build Coastguard Worker }
140*4d7e907cSAndroid Build Coastguard Worker 
141*4d7e907cSAndroid Build Coastguard Worker 
startVideoStream(const::android::sp<IEvsCameraStream> & stream)142*4d7e907cSAndroid Build Coastguard Worker Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStream>& stream)  {
143*4d7e907cSAndroid Build Coastguard Worker     ALOGD("startVideoStream");
144*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mAccessLock);
145*4d7e907cSAndroid Build Coastguard Worker 
146*4d7e907cSAndroid Build Coastguard Worker     // If we've been displaced by another owner of the camera, then we can't do anything else
147*4d7e907cSAndroid Build Coastguard Worker     if (mStreamState == DEAD) {
148*4d7e907cSAndroid Build Coastguard Worker         ALOGE("ignoring startVideoStream call when camera has been lost.");
149*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::OWNERSHIP_LOST;
150*4d7e907cSAndroid Build Coastguard Worker     }
151*4d7e907cSAndroid Build Coastguard Worker     if (mStreamState != STOPPED) {
152*4d7e907cSAndroid Build Coastguard Worker         ALOGE("ignoring startVideoStream call when a stream is already running.");
153*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::STREAM_ALREADY_RUNNING;
154*4d7e907cSAndroid Build Coastguard Worker     }
155*4d7e907cSAndroid Build Coastguard Worker 
156*4d7e907cSAndroid Build Coastguard Worker     // If the client never indicated otherwise, configure ourselves for a single streaming buffer
157*4d7e907cSAndroid Build Coastguard Worker     if (mFramesAllowed < 1) {
158*4d7e907cSAndroid Build Coastguard Worker         if (!setAvailableFrames_Locked(1)) {
159*4d7e907cSAndroid Build Coastguard Worker             ALOGE("Failed to start stream because we couldn't get a graphics buffer");
160*4d7e907cSAndroid Build Coastguard Worker             return EvsResult::BUFFER_NOT_AVAILABLE;
161*4d7e907cSAndroid Build Coastguard Worker         }
162*4d7e907cSAndroid Build Coastguard Worker     }
163*4d7e907cSAndroid Build Coastguard Worker 
164*4d7e907cSAndroid Build Coastguard Worker     // Record the user's callback for use when we have a frame ready
165*4d7e907cSAndroid Build Coastguard Worker     mStream = stream;
166*4d7e907cSAndroid Build Coastguard Worker 
167*4d7e907cSAndroid Build Coastguard Worker     // Start the frame generation thread
168*4d7e907cSAndroid Build Coastguard Worker     mStreamState = RUNNING;
169*4d7e907cSAndroid Build Coastguard Worker     mCaptureThread = std::thread([this](){ generateFrames(); });
170*4d7e907cSAndroid Build Coastguard Worker 
171*4d7e907cSAndroid Build Coastguard Worker     return EvsResult::OK;
172*4d7e907cSAndroid Build Coastguard Worker }
173*4d7e907cSAndroid Build Coastguard Worker 
174*4d7e907cSAndroid Build Coastguard Worker 
doneWithFrame(const BufferDesc & buffer)175*4d7e907cSAndroid Build Coastguard Worker Return<void> EvsCamera::doneWithFrame(const BufferDesc& buffer)  {
176*4d7e907cSAndroid Build Coastguard Worker     ALOGD("doneWithFrame");
177*4d7e907cSAndroid Build Coastguard Worker     {  // lock context
178*4d7e907cSAndroid Build Coastguard Worker         std::lock_guard <std::mutex> lock(mAccessLock);
179*4d7e907cSAndroid Build Coastguard Worker 
180*4d7e907cSAndroid Build Coastguard Worker         if (buffer.memHandle == nullptr) {
181*4d7e907cSAndroid Build Coastguard Worker             ALOGE("ignoring doneWithFrame called with null handle");
182*4d7e907cSAndroid Build Coastguard Worker         } else if (buffer.bufferId >= mBuffers.size()) {
183*4d7e907cSAndroid Build Coastguard Worker             ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)",
184*4d7e907cSAndroid Build Coastguard Worker                   buffer.bufferId, mBuffers.size()-1);
185*4d7e907cSAndroid Build Coastguard Worker         } else if (!mBuffers[buffer.bufferId].inUse) {
186*4d7e907cSAndroid Build Coastguard Worker             ALOGE("ignoring doneWithFrame called on frame %d which is already free",
187*4d7e907cSAndroid Build Coastguard Worker                   buffer.bufferId);
188*4d7e907cSAndroid Build Coastguard Worker         } else {
189*4d7e907cSAndroid Build Coastguard Worker             // Mark the frame as available
190*4d7e907cSAndroid Build Coastguard Worker             mBuffers[buffer.bufferId].inUse = false;
191*4d7e907cSAndroid Build Coastguard Worker             mFramesInUse--;
192*4d7e907cSAndroid Build Coastguard Worker 
193*4d7e907cSAndroid Build Coastguard Worker             // If this frame's index is high in the array, try to move it down
194*4d7e907cSAndroid Build Coastguard Worker             // to improve locality after mFramesAllowed has been reduced.
195*4d7e907cSAndroid Build Coastguard Worker             if (buffer.bufferId >= mFramesAllowed) {
196*4d7e907cSAndroid Build Coastguard Worker                 // Find an empty slot lower in the array (which should always exist in this case)
197*4d7e907cSAndroid Build Coastguard Worker                 for (auto&& rec : mBuffers) {
198*4d7e907cSAndroid Build Coastguard Worker                     if (rec.handle == nullptr) {
199*4d7e907cSAndroid Build Coastguard Worker                         rec.handle = mBuffers[buffer.bufferId].handle;
200*4d7e907cSAndroid Build Coastguard Worker                         mBuffers[buffer.bufferId].handle = nullptr;
201*4d7e907cSAndroid Build Coastguard Worker                         break;
202*4d7e907cSAndroid Build Coastguard Worker                     }
203*4d7e907cSAndroid Build Coastguard Worker                 }
204*4d7e907cSAndroid Build Coastguard Worker             }
205*4d7e907cSAndroid Build Coastguard Worker         }
206*4d7e907cSAndroid Build Coastguard Worker     }
207*4d7e907cSAndroid Build Coastguard Worker 
208*4d7e907cSAndroid Build Coastguard Worker     return Void();
209*4d7e907cSAndroid Build Coastguard Worker }
210*4d7e907cSAndroid Build Coastguard Worker 
211*4d7e907cSAndroid Build Coastguard Worker 
stopVideoStream()212*4d7e907cSAndroid Build Coastguard Worker Return<void> EvsCamera::stopVideoStream()  {
213*4d7e907cSAndroid Build Coastguard Worker     ALOGD("stopVideoStream");
214*4d7e907cSAndroid Build Coastguard Worker     std::unique_lock <std::mutex> lock(mAccessLock);
215*4d7e907cSAndroid Build Coastguard Worker 
216*4d7e907cSAndroid Build Coastguard Worker     if (mStreamState == RUNNING) {
217*4d7e907cSAndroid Build Coastguard Worker         // Tell the GenerateFrames loop we want it to stop
218*4d7e907cSAndroid Build Coastguard Worker         mStreamState = STOPPING;
219*4d7e907cSAndroid Build Coastguard Worker 
220*4d7e907cSAndroid Build Coastguard Worker         // Block outside the mutex until the "stop" flag has been acknowledged
221*4d7e907cSAndroid Build Coastguard Worker         // We won't send any more frames, but the client might still get some already in flight
222*4d7e907cSAndroid Build Coastguard Worker         ALOGD("Waiting for stream thread to end...");
223*4d7e907cSAndroid Build Coastguard Worker         lock.unlock();
224*4d7e907cSAndroid Build Coastguard Worker         mCaptureThread.join();
225*4d7e907cSAndroid Build Coastguard Worker         lock.lock();
226*4d7e907cSAndroid Build Coastguard Worker 
227*4d7e907cSAndroid Build Coastguard Worker         mStreamState = STOPPED;
228*4d7e907cSAndroid Build Coastguard Worker         mStream = nullptr;
229*4d7e907cSAndroid Build Coastguard Worker         ALOGD("Stream marked STOPPED.");
230*4d7e907cSAndroid Build Coastguard Worker     }
231*4d7e907cSAndroid Build Coastguard Worker 
232*4d7e907cSAndroid Build Coastguard Worker     return Void();
233*4d7e907cSAndroid Build Coastguard Worker }
234*4d7e907cSAndroid Build Coastguard Worker 
235*4d7e907cSAndroid Build Coastguard Worker 
getExtendedInfo(uint32_t opaqueIdentifier)236*4d7e907cSAndroid Build Coastguard Worker Return<int32_t> EvsCamera::getExtendedInfo(uint32_t opaqueIdentifier)  {
237*4d7e907cSAndroid Build Coastguard Worker     ALOGD("getExtendedInfo");
238*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mAccessLock);
239*4d7e907cSAndroid Build Coastguard Worker 
240*4d7e907cSAndroid Build Coastguard Worker     // For any single digit value, return the index itself as a test value
241*4d7e907cSAndroid Build Coastguard Worker     if (opaqueIdentifier <= 9) {
242*4d7e907cSAndroid Build Coastguard Worker         return opaqueIdentifier;
243*4d7e907cSAndroid Build Coastguard Worker     }
244*4d7e907cSAndroid Build Coastguard Worker 
245*4d7e907cSAndroid Build Coastguard Worker     // Return zero by default as required by the spec
246*4d7e907cSAndroid Build Coastguard Worker     return 0;
247*4d7e907cSAndroid Build Coastguard Worker }
248*4d7e907cSAndroid Build Coastguard Worker 
249*4d7e907cSAndroid Build Coastguard Worker 
setExtendedInfo(uint32_t,int32_t)250*4d7e907cSAndroid Build Coastguard Worker Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int32_t /*opaqueValue*/)  {
251*4d7e907cSAndroid Build Coastguard Worker     ALOGD("setExtendedInfo");
252*4d7e907cSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mAccessLock);
253*4d7e907cSAndroid Build Coastguard Worker 
254*4d7e907cSAndroid Build Coastguard Worker     // If we've been displaced by another owner of the camera, then we can't do anything else
255*4d7e907cSAndroid Build Coastguard Worker     if (mStreamState == DEAD) {
256*4d7e907cSAndroid Build Coastguard Worker         ALOGE("ignoring setExtendedInfo call when camera has been lost.");
257*4d7e907cSAndroid Build Coastguard Worker         return EvsResult::OWNERSHIP_LOST;
258*4d7e907cSAndroid Build Coastguard Worker     }
259*4d7e907cSAndroid Build Coastguard Worker 
260*4d7e907cSAndroid Build Coastguard Worker     // We don't store any device specific information in this implementation
261*4d7e907cSAndroid Build Coastguard Worker     return EvsResult::INVALID_ARG;
262*4d7e907cSAndroid Build Coastguard Worker }
263*4d7e907cSAndroid Build Coastguard Worker 
264*4d7e907cSAndroid Build Coastguard Worker 
setAvailableFrames_Locked(unsigned bufferCount)265*4d7e907cSAndroid Build Coastguard Worker bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
266*4d7e907cSAndroid Build Coastguard Worker     if (bufferCount < 1) {
267*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Ignoring request to set buffer count to zero");
268*4d7e907cSAndroid Build Coastguard Worker         return false;
269*4d7e907cSAndroid Build Coastguard Worker     }
270*4d7e907cSAndroid Build Coastguard Worker     if (bufferCount > MAX_BUFFERS_IN_FLIGHT) {
271*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Rejecting buffer request in excess of internal limit");
272*4d7e907cSAndroid Build Coastguard Worker         return false;
273*4d7e907cSAndroid Build Coastguard Worker     }
274*4d7e907cSAndroid Build Coastguard Worker 
275*4d7e907cSAndroid Build Coastguard Worker     // Is an increase required?
276*4d7e907cSAndroid Build Coastguard Worker     if (mFramesAllowed < bufferCount) {
277*4d7e907cSAndroid Build Coastguard Worker         // An increase is required
278*4d7e907cSAndroid Build Coastguard Worker         unsigned needed = bufferCount - mFramesAllowed;
279*4d7e907cSAndroid Build Coastguard Worker         ALOGI("Allocating %d buffers for camera frames", needed);
280*4d7e907cSAndroid Build Coastguard Worker 
281*4d7e907cSAndroid Build Coastguard Worker         unsigned added = increaseAvailableFrames_Locked(needed);
282*4d7e907cSAndroid Build Coastguard Worker         if (added != needed) {
283*4d7e907cSAndroid Build Coastguard Worker             // If we didn't add all the frames we needed, then roll back to the previous state
284*4d7e907cSAndroid Build Coastguard Worker             ALOGE("Rolling back to previous frame queue size");
285*4d7e907cSAndroid Build Coastguard Worker             decreaseAvailableFrames_Locked(added);
286*4d7e907cSAndroid Build Coastguard Worker             return false;
287*4d7e907cSAndroid Build Coastguard Worker         }
288*4d7e907cSAndroid Build Coastguard Worker     } else if (mFramesAllowed > bufferCount) {
289*4d7e907cSAndroid Build Coastguard Worker         // A decrease is required
290*4d7e907cSAndroid Build Coastguard Worker         unsigned framesToRelease = mFramesAllowed - bufferCount;
291*4d7e907cSAndroid Build Coastguard Worker         ALOGI("Returning %d camera frame buffers", framesToRelease);
292*4d7e907cSAndroid Build Coastguard Worker 
293*4d7e907cSAndroid Build Coastguard Worker         unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
294*4d7e907cSAndroid Build Coastguard Worker         if (released != framesToRelease) {
295*4d7e907cSAndroid Build Coastguard Worker             // This shouldn't happen with a properly behaving client because the client
296*4d7e907cSAndroid Build Coastguard Worker             // should only make this call after returning sufficient outstanding buffers
297*4d7e907cSAndroid Build Coastguard Worker             // to allow a clean resize.
298*4d7e907cSAndroid Build Coastguard Worker             ALOGE("Buffer queue shrink failed -- too many buffers currently in use?");
299*4d7e907cSAndroid Build Coastguard Worker         }
300*4d7e907cSAndroid Build Coastguard Worker     }
301*4d7e907cSAndroid Build Coastguard Worker 
302*4d7e907cSAndroid Build Coastguard Worker     return true;
303*4d7e907cSAndroid Build Coastguard Worker }
304*4d7e907cSAndroid Build Coastguard Worker 
305*4d7e907cSAndroid Build Coastguard Worker 
increaseAvailableFrames_Locked(unsigned numToAdd)306*4d7e907cSAndroid Build Coastguard Worker unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
307*4d7e907cSAndroid Build Coastguard Worker     // Acquire the graphics buffer allocator
308*4d7e907cSAndroid Build Coastguard Worker     GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
309*4d7e907cSAndroid Build Coastguard Worker 
310*4d7e907cSAndroid Build Coastguard Worker     unsigned added = 0;
311*4d7e907cSAndroid Build Coastguard Worker 
312*4d7e907cSAndroid Build Coastguard Worker     while (added < numToAdd) {
313*4d7e907cSAndroid Build Coastguard Worker         buffer_handle_t memHandle = nullptr;
314*4d7e907cSAndroid Build Coastguard Worker         status_t result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage,
315*4d7e907cSAndroid Build Coastguard Worker                                          &memHandle, &mStride, 0, "EvsCamera");
316*4d7e907cSAndroid Build Coastguard Worker         if (result != NO_ERROR) {
317*4d7e907cSAndroid Build Coastguard Worker             ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight);
318*4d7e907cSAndroid Build Coastguard Worker             break;
319*4d7e907cSAndroid Build Coastguard Worker         }
320*4d7e907cSAndroid Build Coastguard Worker         if (!memHandle) {
321*4d7e907cSAndroid Build Coastguard Worker             ALOGE("We didn't get a buffer handle back from the allocator");
322*4d7e907cSAndroid Build Coastguard Worker             break;
323*4d7e907cSAndroid Build Coastguard Worker         }
324*4d7e907cSAndroid Build Coastguard Worker 
325*4d7e907cSAndroid Build Coastguard Worker         // Find a place to store the new buffer
326*4d7e907cSAndroid Build Coastguard Worker         bool stored = false;
327*4d7e907cSAndroid Build Coastguard Worker         for (auto&& rec : mBuffers) {
328*4d7e907cSAndroid Build Coastguard Worker             if (rec.handle == nullptr) {
329*4d7e907cSAndroid Build Coastguard Worker                 // Use this existing entry
330*4d7e907cSAndroid Build Coastguard Worker                 rec.handle = memHandle;
331*4d7e907cSAndroid Build Coastguard Worker                 rec.inUse = false;
332*4d7e907cSAndroid Build Coastguard Worker                 stored = true;
333*4d7e907cSAndroid Build Coastguard Worker                 break;
334*4d7e907cSAndroid Build Coastguard Worker             }
335*4d7e907cSAndroid Build Coastguard Worker         }
336*4d7e907cSAndroid Build Coastguard Worker         if (!stored) {
337*4d7e907cSAndroid Build Coastguard Worker             // Add a BufferRecord wrapping this handle to our set of available buffers
338*4d7e907cSAndroid Build Coastguard Worker             mBuffers.emplace_back(memHandle);
339*4d7e907cSAndroid Build Coastguard Worker         }
340*4d7e907cSAndroid Build Coastguard Worker 
341*4d7e907cSAndroid Build Coastguard Worker         mFramesAllowed++;
342*4d7e907cSAndroid Build Coastguard Worker         added++;
343*4d7e907cSAndroid Build Coastguard Worker     }
344*4d7e907cSAndroid Build Coastguard Worker 
345*4d7e907cSAndroid Build Coastguard Worker     return added;
346*4d7e907cSAndroid Build Coastguard Worker }
347*4d7e907cSAndroid Build Coastguard Worker 
348*4d7e907cSAndroid Build Coastguard Worker 
decreaseAvailableFrames_Locked(unsigned numToRemove)349*4d7e907cSAndroid Build Coastguard Worker unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
350*4d7e907cSAndroid Build Coastguard Worker     // Acquire the graphics buffer allocator
351*4d7e907cSAndroid Build Coastguard Worker     GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
352*4d7e907cSAndroid Build Coastguard Worker 
353*4d7e907cSAndroid Build Coastguard Worker     unsigned removed = 0;
354*4d7e907cSAndroid Build Coastguard Worker 
355*4d7e907cSAndroid Build Coastguard Worker     for (auto&& rec : mBuffers) {
356*4d7e907cSAndroid Build Coastguard Worker         // Is this record not in use, but holding a buffer that we can free?
357*4d7e907cSAndroid Build Coastguard Worker         if ((rec.inUse == false) && (rec.handle != nullptr)) {
358*4d7e907cSAndroid Build Coastguard Worker             // Release buffer and update the record so we can recognize it as "empty"
359*4d7e907cSAndroid Build Coastguard Worker             alloc.free(rec.handle);
360*4d7e907cSAndroid Build Coastguard Worker             rec.handle = nullptr;
361*4d7e907cSAndroid Build Coastguard Worker 
362*4d7e907cSAndroid Build Coastguard Worker             mFramesAllowed--;
363*4d7e907cSAndroid Build Coastguard Worker             removed++;
364*4d7e907cSAndroid Build Coastguard Worker 
365*4d7e907cSAndroid Build Coastguard Worker             if (removed == numToRemove) {
366*4d7e907cSAndroid Build Coastguard Worker                 break;
367*4d7e907cSAndroid Build Coastguard Worker             }
368*4d7e907cSAndroid Build Coastguard Worker         }
369*4d7e907cSAndroid Build Coastguard Worker     }
370*4d7e907cSAndroid Build Coastguard Worker 
371*4d7e907cSAndroid Build Coastguard Worker     return removed;
372*4d7e907cSAndroid Build Coastguard Worker }
373*4d7e907cSAndroid Build Coastguard Worker 
374*4d7e907cSAndroid Build Coastguard Worker 
375*4d7e907cSAndroid Build Coastguard Worker // This is the asynchronous frame generation thread that runs in parallel with the
376*4d7e907cSAndroid Build Coastguard Worker // main serving thread.  There is one for each active camera instance.
generateFrames()377*4d7e907cSAndroid Build Coastguard Worker void EvsCamera::generateFrames() {
378*4d7e907cSAndroid Build Coastguard Worker     ALOGD("Frame generation loop started");
379*4d7e907cSAndroid Build Coastguard Worker 
380*4d7e907cSAndroid Build Coastguard Worker     unsigned idx;
381*4d7e907cSAndroid Build Coastguard Worker 
382*4d7e907cSAndroid Build Coastguard Worker     while (true) {
383*4d7e907cSAndroid Build Coastguard Worker         bool timeForFrame = false;
384*4d7e907cSAndroid Build Coastguard Worker         nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
385*4d7e907cSAndroid Build Coastguard Worker 
386*4d7e907cSAndroid Build Coastguard Worker         // Lock scope for updating shared state
387*4d7e907cSAndroid Build Coastguard Worker         {
388*4d7e907cSAndroid Build Coastguard Worker             std::lock_guard<std::mutex> lock(mAccessLock);
389*4d7e907cSAndroid Build Coastguard Worker 
390*4d7e907cSAndroid Build Coastguard Worker             if (mStreamState != RUNNING) {
391*4d7e907cSAndroid Build Coastguard Worker                 // Break out of our main thread loop
392*4d7e907cSAndroid Build Coastguard Worker                 break;
393*4d7e907cSAndroid Build Coastguard Worker             }
394*4d7e907cSAndroid Build Coastguard Worker 
395*4d7e907cSAndroid Build Coastguard Worker             // Are we allowed to issue another buffer?
396*4d7e907cSAndroid Build Coastguard Worker             if (mFramesInUse >= mFramesAllowed) {
397*4d7e907cSAndroid Build Coastguard Worker                 // Can't do anything right now -- skip this frame
398*4d7e907cSAndroid Build Coastguard Worker                 ALOGW("Skipped a frame because too many are in flight\n");
399*4d7e907cSAndroid Build Coastguard Worker             } else {
400*4d7e907cSAndroid Build Coastguard Worker                 // Identify an available buffer to fill
401*4d7e907cSAndroid Build Coastguard Worker                 for (idx = 0; idx < mBuffers.size(); idx++) {
402*4d7e907cSAndroid Build Coastguard Worker                     if (!mBuffers[idx].inUse) {
403*4d7e907cSAndroid Build Coastguard Worker                         if (mBuffers[idx].handle != nullptr) {
404*4d7e907cSAndroid Build Coastguard Worker                             // Found an available record, so stop looking
405*4d7e907cSAndroid Build Coastguard Worker                             break;
406*4d7e907cSAndroid Build Coastguard Worker                         }
407*4d7e907cSAndroid Build Coastguard Worker                     }
408*4d7e907cSAndroid Build Coastguard Worker                 }
409*4d7e907cSAndroid Build Coastguard Worker                 if (idx >= mBuffers.size()) {
410*4d7e907cSAndroid Build Coastguard Worker                     // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
411*4d7e907cSAndroid Build Coastguard Worker                     ALOGE("Failed to find an available buffer slot\n");
412*4d7e907cSAndroid Build Coastguard Worker                 } else {
413*4d7e907cSAndroid Build Coastguard Worker                     // We're going to make the frame busy
414*4d7e907cSAndroid Build Coastguard Worker                     mBuffers[idx].inUse = true;
415*4d7e907cSAndroid Build Coastguard Worker                     mFramesInUse++;
416*4d7e907cSAndroid Build Coastguard Worker                     timeForFrame = true;
417*4d7e907cSAndroid Build Coastguard Worker                 }
418*4d7e907cSAndroid Build Coastguard Worker             }
419*4d7e907cSAndroid Build Coastguard Worker         }
420*4d7e907cSAndroid Build Coastguard Worker 
421*4d7e907cSAndroid Build Coastguard Worker         if (timeForFrame) {
422*4d7e907cSAndroid Build Coastguard Worker             // Assemble the buffer description we'll transmit below
423*4d7e907cSAndroid Build Coastguard Worker             BufferDesc buff = {};
424*4d7e907cSAndroid Build Coastguard Worker             buff.width      = mWidth;
425*4d7e907cSAndroid Build Coastguard Worker             buff.height     = mHeight;
426*4d7e907cSAndroid Build Coastguard Worker             buff.stride     = mStride;
427*4d7e907cSAndroid Build Coastguard Worker             buff.format     = mFormat;
428*4d7e907cSAndroid Build Coastguard Worker             buff.usage      = mUsage;
429*4d7e907cSAndroid Build Coastguard Worker             buff.bufferId   = idx;
430*4d7e907cSAndroid Build Coastguard Worker             buff.memHandle  = mBuffers[idx].handle;
431*4d7e907cSAndroid Build Coastguard Worker 
432*4d7e907cSAndroid Build Coastguard Worker             // Write test data into the image buffer
433*4d7e907cSAndroid Build Coastguard Worker             fillTestFrame(buff);
434*4d7e907cSAndroid Build Coastguard Worker 
435*4d7e907cSAndroid Build Coastguard Worker             // Issue the (asynchronous) callback to the client -- can't be holding the lock
436*4d7e907cSAndroid Build Coastguard Worker             auto result = mStream->deliverFrame(buff);
437*4d7e907cSAndroid Build Coastguard Worker             if (result.isOk()) {
438*4d7e907cSAndroid Build Coastguard Worker                 ALOGD("Delivered %p as id %d", buff.memHandle.getNativeHandle(), buff.bufferId);
439*4d7e907cSAndroid Build Coastguard Worker             } else {
440*4d7e907cSAndroid Build Coastguard Worker                 // This can happen if the client dies and is likely unrecoverable.
441*4d7e907cSAndroid Build Coastguard Worker                 // To avoid consuming resources generating failing calls, we stop sending
442*4d7e907cSAndroid Build Coastguard Worker                 // frames.  Note, however, that the stream remains in the "STREAMING" state
443*4d7e907cSAndroid Build Coastguard Worker                 // until cleaned up on the main thread.
444*4d7e907cSAndroid Build Coastguard Worker                 ALOGE("Frame delivery call failed in the transport layer.");
445*4d7e907cSAndroid Build Coastguard Worker 
446*4d7e907cSAndroid Build Coastguard Worker                 // Since we didn't actually deliver it, mark the frame as available
447*4d7e907cSAndroid Build Coastguard Worker                 std::lock_guard<std::mutex> lock(mAccessLock);
448*4d7e907cSAndroid Build Coastguard Worker                 mBuffers[idx].inUse = false;
449*4d7e907cSAndroid Build Coastguard Worker                 mFramesInUse--;
450*4d7e907cSAndroid Build Coastguard Worker 
451*4d7e907cSAndroid Build Coastguard Worker                 break;
452*4d7e907cSAndroid Build Coastguard Worker             }
453*4d7e907cSAndroid Build Coastguard Worker         }
454*4d7e907cSAndroid Build Coastguard Worker 
455*4d7e907cSAndroid Build Coastguard Worker         // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement
456*4d7e907cSAndroid Build Coastguard Worker         static const int kTargetFrameRate = 12;
457*4d7e907cSAndroid Build Coastguard Worker         static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate;
458*4d7e907cSAndroid Build Coastguard Worker         const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
459*4d7e907cSAndroid Build Coastguard Worker         const nsecs_t workTimeUs = (now - startTime) / 1000;
460*4d7e907cSAndroid Build Coastguard Worker         const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
461*4d7e907cSAndroid Build Coastguard Worker         if (sleepDurationUs > 0) {
462*4d7e907cSAndroid Build Coastguard Worker             usleep(sleepDurationUs);
463*4d7e907cSAndroid Build Coastguard Worker         }
464*4d7e907cSAndroid Build Coastguard Worker     }
465*4d7e907cSAndroid Build Coastguard Worker 
466*4d7e907cSAndroid Build Coastguard Worker     // If we've been asked to stop, send one last NULL frame to signal the actual end of stream
467*4d7e907cSAndroid Build Coastguard Worker     BufferDesc nullBuff = {};
468*4d7e907cSAndroid Build Coastguard Worker     auto result = mStream->deliverFrame(nullBuff);
469*4d7e907cSAndroid Build Coastguard Worker     if (!result.isOk()) {
470*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Error delivering end of stream marker");
471*4d7e907cSAndroid Build Coastguard Worker     }
472*4d7e907cSAndroid Build Coastguard Worker 
473*4d7e907cSAndroid Build Coastguard Worker     return;
474*4d7e907cSAndroid Build Coastguard Worker }
475*4d7e907cSAndroid Build Coastguard Worker 
476*4d7e907cSAndroid Build Coastguard Worker 
fillTestFrame(const BufferDesc & buff)477*4d7e907cSAndroid Build Coastguard Worker void EvsCamera::fillTestFrame(const BufferDesc& buff) {
478*4d7e907cSAndroid Build Coastguard Worker     // Lock our output buffer for writing
479*4d7e907cSAndroid Build Coastguard Worker     uint32_t *pixels = nullptr;
480*4d7e907cSAndroid Build Coastguard Worker     GraphicBufferMapper &mapper = GraphicBufferMapper::get();
481*4d7e907cSAndroid Build Coastguard Worker     mapper.lock(buff.memHandle,
482*4d7e907cSAndroid Build Coastguard Worker                 GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
483*4d7e907cSAndroid Build Coastguard Worker                 android::Rect(buff.width, buff.height),
484*4d7e907cSAndroid Build Coastguard Worker                 (void **) &pixels);
485*4d7e907cSAndroid Build Coastguard Worker 
486*4d7e907cSAndroid Build Coastguard Worker     // If we failed to lock the pixel buffer, we're about to crash, but log it first
487*4d7e907cSAndroid Build Coastguard Worker     if (!pixels) {
488*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Camera failed to gain access to image buffer for writing");
489*4d7e907cSAndroid Build Coastguard Worker     }
490*4d7e907cSAndroid Build Coastguard Worker 
491*4d7e907cSAndroid Build Coastguard Worker     // Fill in the test pixels
492*4d7e907cSAndroid Build Coastguard Worker     for (unsigned row = 0; row < buff.height; row++) {
493*4d7e907cSAndroid Build Coastguard Worker         for (unsigned col = 0; col < buff.width; col++) {
494*4d7e907cSAndroid Build Coastguard Worker             // Index into the row to check the pixel at this column.
495*4d7e907cSAndroid Build Coastguard Worker             // We expect 0xFF in the LSB channel, a vertical gradient in the
496*4d7e907cSAndroid Build Coastguard Worker             // second channel, a horitzontal gradient in the third channel, and
497*4d7e907cSAndroid Build Coastguard Worker             // 0xFF in the MSB.
498*4d7e907cSAndroid Build Coastguard Worker             // The exception is the very first 32 bits which is used for the
499*4d7e907cSAndroid Build Coastguard Worker             // time varying frame signature to avoid getting fooled by a static image.
500*4d7e907cSAndroid Build Coastguard Worker             uint32_t expectedPixel = 0xFF0000FF           | // MSB and LSB
501*4d7e907cSAndroid Build Coastguard Worker                                      ((row & 0xFF) <<  8) | // vertical gradient
502*4d7e907cSAndroid Build Coastguard Worker                                      ((col & 0xFF) << 16);  // horizontal gradient
503*4d7e907cSAndroid Build Coastguard Worker             if ((row | col) == 0) {
504*4d7e907cSAndroid Build Coastguard Worker                 static uint32_t sFrameTicker = 0;
505*4d7e907cSAndroid Build Coastguard Worker                 expectedPixel = (sFrameTicker) & 0xFF;
506*4d7e907cSAndroid Build Coastguard Worker                 sFrameTicker++;
507*4d7e907cSAndroid Build Coastguard Worker             }
508*4d7e907cSAndroid Build Coastguard Worker             pixels[col] = expectedPixel;
509*4d7e907cSAndroid Build Coastguard Worker         }
510*4d7e907cSAndroid Build Coastguard Worker         // Point to the next row
511*4d7e907cSAndroid Build Coastguard Worker         // NOTE:  stride retrieved from gralloc is in units of pixels
512*4d7e907cSAndroid Build Coastguard Worker         pixels = pixels + buff.stride;
513*4d7e907cSAndroid Build Coastguard Worker     }
514*4d7e907cSAndroid Build Coastguard Worker 
515*4d7e907cSAndroid Build Coastguard Worker     // Release our output buffer
516*4d7e907cSAndroid Build Coastguard Worker     mapper.unlock(buff.memHandle);
517*4d7e907cSAndroid Build Coastguard Worker }
518*4d7e907cSAndroid Build Coastguard Worker 
519*4d7e907cSAndroid Build Coastguard Worker 
520*4d7e907cSAndroid Build Coastguard Worker } // namespace implementation
521*4d7e907cSAndroid Build Coastguard Worker } // namespace V1_0
522*4d7e907cSAndroid Build Coastguard Worker } // namespace evs
523*4d7e907cSAndroid Build Coastguard Worker } // namespace automotive
524*4d7e907cSAndroid Build Coastguard Worker } // namespace hardware
525*4d7e907cSAndroid Build Coastguard Worker } // namespace android
526