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