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