1 /*
2  * Copyright (C) 2017 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 #include "StreamHandler.h"
18 
19 #include "Frame.h"
20 #include "ResourceManager.h"
21 
22 #include <cutils/native_handle.h>
23 #include <log/log.h>
24 #include <ui/GraphicBufferAllocator.h>
25 #include <ui/GraphicBufferMapper.h>
26 
27 #include <stdio.h>
28 #include <string.h>
29 
30 namespace android {
31 namespace automotive {
32 namespace evs {
33 namespace support {
34 
35 using ::android::hardware::automotive::evs::V1_0::EvsResult;
36 using ::std::lock_guard;
37 using ::std::unique_lock;
38 
StreamHandler(android::sp<IEvsCamera> pCamera)39 StreamHandler::StreamHandler(android::sp<IEvsCamera> pCamera) :
40       mCamera(pCamera), mAnalyzeCallback(nullptr), mAnalyzerRunning(false) {
41     // We rely on the camera having at least two buffers available since we'll hold one and
42     // expect the camera to be able to capture a new image in the background.
43     pCamera->setMaxFramesInFlight(2);
44 }
45 
46 // TODO(b/130246343): investigate further to make sure the resources are cleaned
47 // up properly in the shutdown logic.
shutdown()48 void StreamHandler::shutdown() {
49     // Tell the camera to stop streaming.
50     // This will result in a null frame being delivered when the stream actually stops.
51     mCamera->stopVideoStream();
52 
53     // Wait until the stream has actually stopped
54     unique_lock<mutex> lock(mLock);
55     if (mRunning) {
56         mSignal.wait(lock, [this]() { return !mRunning; });
57     }
58 
59     // At this point, the receiver thread is no longer running, so we can safely drop
60     // our remote object references so they can be freed
61     mCamera = nullptr;
62 }
63 
startStream()64 bool StreamHandler::startStream() {
65     lock_guard<mutex> lock(mLock);
66 
67     if (!mRunning) {
68         // Tell the camera to start streaming
69         Return<EvsResult> result = mCamera->startVideoStream(this);
70         if (result != EvsResult::OK) {
71             return false;
72         }
73 
74         // Mark ourselves as running
75         mRunning = true;
76     }
77 
78     return true;
79 }
80 
newDisplayFrameAvailable()81 bool StreamHandler::newDisplayFrameAvailable() {
82     lock_guard<mutex> lock(mLock);
83     return (mReadyBuffer >= 0);
84 }
85 
getNewDisplayFrame()86 const BufferDesc& StreamHandler::getNewDisplayFrame() {
87     lock_guard<mutex> lock(mLock);
88 
89     if (mHeldBuffer >= 0) {
90         ALOGE("Ignored call for new frame while still holding the old one.");
91     } else {
92         if (mReadyBuffer < 0) {
93             ALOGE("Returning invalid buffer because we don't have any. "
94                   " Call newDisplayFrameAvailable first?");
95             mReadyBuffer = 0;  // This is a lie!
96         }
97 
98         // Move the ready buffer into the held position, and clear the ready position
99         mHeldBuffer = mReadyBuffer;
100         mReadyBuffer = -1;
101     }
102 
103     if (mRenderCallback == nullptr) {
104         return mOriginalBuffers[mHeldBuffer];
105     } else {
106         return mProcessedBuffers[mHeldBuffer];
107     }
108 }
109 
doneWithFrame(const BufferDesc & buffer)110 void StreamHandler::doneWithFrame(const BufferDesc& buffer) {
111     lock_guard<mutex> lock(mLock);
112 
113     // We better be getting back the buffer we original delivered!
114     if ((mHeldBuffer < 0) || (buffer.bufferId != mOriginalBuffers[mHeldBuffer].bufferId)) {
115         ALOGE("StreamHandler::doneWithFrame got an unexpected buffer!");
116         ALOGD("Held buffer id: %d, input buffer id: %d", mOriginalBuffers[mHeldBuffer].bufferId,
117               buffer.bufferId);
118         return;
119     }
120 
121     // Send the buffer back to the underlying camera
122     mCamera->doneWithFrame(mOriginalBuffers[mHeldBuffer]);
123 
124     // Clear the held position
125     mHeldBuffer = -1;
126 }
127 
deliverFrame(const BufferDesc & buffer)128 Return<void> StreamHandler::deliverFrame(const BufferDesc& buffer) {
129     ALOGD("Received a frame from the camera. NativeHandle:%p, buffer id:%d",
130           buffer.memHandle.getNativeHandle(), buffer.bufferId);
131 
132     // Take the lock to protect our frame slots and running state variable
133     {
134         lock_guard<mutex> lock(mLock);
135 
136         if (buffer.memHandle.getNativeHandle() == nullptr) {
137             // Signal that the last frame has been received and the stream is stopped
138             mRunning = false;
139         } else {
140             // Do we already have a "ready" frame?
141             if (mReadyBuffer >= 0) {
142                 // Send the previously saved buffer back to the camera unused
143                 mCamera->doneWithFrame(mOriginalBuffers[mReadyBuffer]);
144 
145                 // We'll reuse the same ready buffer index
146             } else if (mHeldBuffer >= 0) {
147                 // The client is holding a buffer, so use the other slot for "on deck"
148                 mReadyBuffer = 1 - mHeldBuffer;
149             } else {
150                 // This is our first buffer, so just pick a slot
151                 mReadyBuffer = 0;
152             }
153 
154             // Save this frame until our client is interested in it
155             mOriginalBuffers[mReadyBuffer] = buffer;
156 
157             // If render callback is not null, process the frame with render
158             // callback.
159             if (mRenderCallback != nullptr) {
160                 processFrame(mOriginalBuffers[mReadyBuffer], mProcessedBuffers[mReadyBuffer]);
161             } else {
162                 ALOGI("Render callback is null in deliverFrame.");
163             }
164 
165             // If analyze callback is not null and the analyze thread is
166             // available, copy the frame and run the analyze callback in
167             // analyze thread.
168             {
169                 std::shared_lock<std::shared_mutex> analyzerLock(mAnalyzerLock);
170                 if (mAnalyzeCallback != nullptr && !mAnalyzerRunning) {
171                     copyAndAnalyzeFrame(mOriginalBuffers[mReadyBuffer]);
172                 }
173             }
174         }
175     }
176 
177     // Notify anybody who cares that things have changed
178     mSignal.notify_all();
179 
180     return Void();
181 }
182 
attachRenderCallback(BaseRenderCallback * callback)183 void StreamHandler::attachRenderCallback(BaseRenderCallback* callback) {
184     ALOGD("StreamHandler::attachRenderCallback");
185 
186     lock_guard<mutex> lock(mLock);
187 
188     if (mRenderCallback != nullptr) {
189         ALOGW("Ignored! There should only be one render callback");
190         return;
191     }
192     mRenderCallback = callback;
193 }
194 
detachRenderCallback()195 void StreamHandler::detachRenderCallback() {
196     ALOGD("StreamHandler::detachRenderCallback");
197 
198     lock_guard<mutex> lock(mLock);
199 
200     mRenderCallback = nullptr;
201 }
202 
attachAnalyzeCallback(BaseAnalyzeCallback * callback)203 void StreamHandler::attachAnalyzeCallback(BaseAnalyzeCallback* callback) {
204     ALOGD("StreamHandler::attachAnalyzeCallback");
205 
206     if (mAnalyzeCallback != nullptr) {
207         ALOGW("Ignored! There should only be one analyze callcack");
208         return;
209     }
210 
211     {
212         lock_guard<std::shared_mutex> lock(mAnalyzerLock);
213         mAnalyzeCallback = callback;
214     }
215 }
216 
detachAnalyzeCallback()217 void StreamHandler::detachAnalyzeCallback() {
218     ALOGD("StreamHandler::detachAnalyzeCallback");
219 
220     {
221         std::unique_lock<std::shared_mutex> lock(mAnalyzerLock);
222 
223         // Wait until current running analyzer ends
224         mAnalyzerSignal.wait(lock, [this] { return !mAnalyzerRunning; });
225         mAnalyzeCallback = nullptr;
226     }
227 }
228 
isSameFormat(const BufferDesc & input,const BufferDesc & output)229 bool isSameFormat(const BufferDesc& input, const BufferDesc& output) {
230     return input.width == output.width && input.height == output.height &&
231             input.format == output.format && input.usage == output.usage &&
232             input.stride == output.stride && input.pixelSize == output.pixelSize;
233 }
234 
allocate(BufferDesc & buffer)235 bool allocate(BufferDesc& buffer) {
236     ALOGD("StreamHandler::allocate");
237     buffer_handle_t handle;
238     android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
239     android::status_t result =
240             alloc.allocate(buffer.width, buffer.height, buffer.format, 1, buffer.usage, &handle,
241                            &buffer.stride, 0, "EvsDisplay");
242     if (result != android::NO_ERROR) {
243         ALOGE("Error %d allocating %d x %d graphics buffer", result, buffer.width, buffer.height);
244         return false;
245     }
246 
247     // The reason that we have to check null for "handle" is because that the
248     // above "result" might not cover all the failure scenarios.
249     // By looking into Gralloc4.cpp (and 3, 2, as well), it turned out that if
250     // there is anything that goes wrong in the process of buffer importing (see
251     // Ln 385 in Gralloc4.cpp), the error won't be covered by the above "result"
252     // we got from "allocate" method. In other words, it means that there is
253     // still a chance that the "result" is "NO_ERROR" but the handle is nullptr
254     // (that means buffer importing failed).
255     if (!handle) {
256         ALOGE("We didn't get a buffer handle back from the allocator");
257         return false;
258     }
259 
260     buffer.memHandle = hidl_handle(handle);
261     return true;
262 }
263 
processFrame(const BufferDesc & input,BufferDesc & output)264 bool StreamHandler::processFrame(const BufferDesc& input, BufferDesc& output) {
265     ALOGD("StreamHandler::processFrame");
266     if (!isSameFormat(input, output) || output.memHandle.getNativeHandle() == nullptr) {
267         output.width = input.width;
268         output.height = input.height;
269         output.format = input.format;
270         output.usage = input.usage;
271         output.stride = input.stride;
272         output.pixelSize = input.pixelSize;
273 
274         // free the allocated output frame handle if it is not null
275         if (output.memHandle.getNativeHandle() != nullptr) {
276             GraphicBufferAllocator::get().free(output.memHandle);
277         }
278 
279         if (!allocate(output)) {
280             ALOGE("Error allocating buffer");
281             return false;
282         }
283     }
284     output.bufferId = input.bufferId;
285 
286     // Create a GraphicBuffer from the existing handle
287     sp<GraphicBuffer> inputBuffer =
288             new GraphicBuffer(input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
289                               input.height, input.format, 1,  // layer count
290                               GRALLOC_USAGE_HW_TEXTURE, input.stride);
291 
292     if (inputBuffer.get() == nullptr) {
293         ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
294         // Returning "true" in this error condition because we already released
295         // the previous image (if any) and so the texture may change in
296         // unpredictable ways now!
297         return false;
298     }
299 
300     // Lock the input GraphicBuffer and map it to a pointer. If we failed to
301     // lock, return false.
302     void* inputDataPtr;
303     inputBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, &inputDataPtr);
304 
305     // Unlock the buffer and return if lock did not succeed.
306     if (!inputDataPtr) {
307         ALOGE("Failed to gain read access to image buffer");
308 
309         // The program reaches at here when it fails to lock the buffer. But
310         // it is still safer to unlock it. The reason is as described in "lock"
311         // method in  Gralloc.h: "The ownership of acquireFence is always
312         // transferred to the callee, even on errors."
313         // And even if the buffer was not locked, it does not harm anything
314         // given the comment for "unlock" method in IMapper.hal:
315         // "`BAD_BUFFER` if the buffer is invalid or not locked."
316         inputBuffer->unlock();
317         return false;
318     }
319 
320     // Lock the allocated buffer in output BufferDesc and map it to a pointer
321     void* outputDataPtr = nullptr;
322     android::GraphicBufferMapper& mapper = android::GraphicBufferMapper::get();
323     mapper.lock(output.memHandle, GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
324                 android::Rect(output.width, output.height), (void**)&outputDataPtr);
325 
326     // If we failed to lock the pixel buffer, return false, and unlock both
327     // input and output buffers.
328     if (!outputDataPtr) {
329         ALOGE("Failed to gain write access to image buffer");
330 
331         // Please refer to the previous "if" block for why we want to unlock
332         // the buffers even if the buffer locking fails.
333         inputBuffer->unlock();
334         mapper.unlock(output.memHandle);
335         return false;
336     }
337 
338     // Wrap the raw data and copied data, and pass them to the callback.
339     Frame inputFrame = {.width = input.width,
340                         .height = input.height,
341                         .stride = input.stride,
342                         .data = (uint8_t*)inputDataPtr};
343 
344     Frame outputFrame = {.width = output.width,
345                          .height = output.height,
346                          .stride = output.stride,
347                          .data = (uint8_t*)outputDataPtr};
348 
349     mRenderCallback->render(inputFrame, outputFrame);
350 
351     // Unlock the buffers after all changes to the buffer are completed.
352     inputBuffer->unlock();
353     mapper.unlock(output.memHandle);
354 
355     return true;
356 }
357 
copyAndAnalyzeFrame(const BufferDesc & input)358 bool StreamHandler::copyAndAnalyzeFrame(const BufferDesc& input) {
359     ALOGD("StreamHandler::copyAndAnalyzeFrame");
360 
361     // TODO(b/130246434): make the following into a method. Some lines are
362     // duplicated with processFrame, move them into new methods as well.
363     if (!isSameFormat(input, mAnalyzeBuffer) ||
364         mAnalyzeBuffer.memHandle.getNativeHandle() == nullptr) {
365         mAnalyzeBuffer.width = input.width;
366         mAnalyzeBuffer.height = input.height;
367         mAnalyzeBuffer.format = input.format;
368         mAnalyzeBuffer.usage = input.usage;
369         mAnalyzeBuffer.stride = input.stride;
370         mAnalyzeBuffer.pixelSize = input.pixelSize;
371         mAnalyzeBuffer.bufferId = input.bufferId;
372 
373         // free the allocated output frame handle if it is not null
374         if (mAnalyzeBuffer.memHandle.getNativeHandle() != nullptr) {
375             GraphicBufferAllocator::get().free(mAnalyzeBuffer.memHandle);
376         }
377 
378         if (!allocate(mAnalyzeBuffer)) {
379             ALOGE("Error allocating buffer");
380             return false;
381         }
382     }
383 
384     // create a GraphicBuffer from the existing handle
385     sp<GraphicBuffer> inputBuffer =
386             new GraphicBuffer(input.memHandle, GraphicBuffer::CLONE_HANDLE, input.width,
387                               input.height, input.format, 1,  // layer count
388                               GRALLOC_USAGE_HW_TEXTURE, input.stride);
389 
390     if (inputBuffer.get() == nullptr) {
391         ALOGE("Failed to allocate GraphicBuffer to wrap image handle");
392         // Returning "true" in this error condition because we already released the
393         // previous image (if any) and so the texture may change in unpredictable
394         // ways now!
395         return false;
396     }
397 
398     // Lock the input GraphicBuffer and map it to a pointer.  If we failed to
399     // lock, return false.
400     void* inputDataPtr;
401     inputBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, &inputDataPtr);
402     if (!inputDataPtr) {
403         ALOGE("Failed to gain read access to imageGraphicBuffer");
404         inputBuffer->unlock();
405         return false;
406     }
407 
408     // Lock the allocated buffer in output BufferDesc and map it to a pointer
409     void* analyzeDataPtr = nullptr;
410     android::GraphicBufferMapper::get().lock(mAnalyzeBuffer.memHandle,
411                                              GRALLOC_USAGE_SW_WRITE_OFTEN |
412                                                      GRALLOC_USAGE_SW_READ_NEVER,
413                                              android::Rect(mAnalyzeBuffer.width,
414                                                            mAnalyzeBuffer.height),
415                                              (void**)&analyzeDataPtr);
416 
417     // If we failed to lock the pixel buffer, return false, and unlock both
418     // input and output buffers.
419     if (!analyzeDataPtr) {
420         ALOGE("Camera failed to gain access to image buffer for analyzing");
421         return false;
422     }
423 
424     // Wrap the raw data and copied data, and pass them to the callback.
425     Frame analyzeFrame = {
426             .width = mAnalyzeBuffer.width,
427             .height = mAnalyzeBuffer.height,
428             .stride = mAnalyzeBuffer.stride,
429             .data = (uint8_t*)analyzeDataPtr,
430     };
431 
432     memcpy(analyzeDataPtr, inputDataPtr, mAnalyzeBuffer.stride * mAnalyzeBuffer.height * 4);
433 
434     // Unlock the buffers after all changes to the buffer are completed.
435     inputBuffer->unlock();
436 
437     mAnalyzerRunning = true;
438     std::thread([this, analyzeFrame]() {
439         ALOGD("StreamHandler: Analyze Thread starts");
440 
441         std::shared_lock<std::shared_mutex> lock(mAnalyzerLock);
442         if (this->mAnalyzeCallback != nullptr) {
443             this->mAnalyzeCallback->analyze(analyzeFrame);
444             android::GraphicBufferMapper::get().unlock(this->mAnalyzeBuffer.memHandle);
445         }
446         this->mAnalyzerRunning = false;
447         mAnalyzerSignal.notify_one();
448         ALOGD("StreamHandler: Analyze Thread ends");
449     }).detach();
450 
451     return true;
452 }
453 
454 }  // namespace support
455 }  // namespace evs
456 }  // namespace automotive
457 }  // namespace android
458