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 #define LOG_TAG "VtsHalEvsTest"
18 
19 #include "FrameHandler.h"
20 #include "FormatConvert.h"
21 
22 #include <stdio.h>
23 #include <string.h>
24 
25 #include <android/log.h>
26 #include <cutils/native_handle.h>
27 #include <ui/GraphicBuffer.h>
28 
29 
FrameHandler(android::sp<IEvsCamera> pCamera,CameraDesc cameraInfo,android::sp<IEvsDisplay> pDisplay,BufferControlFlag mode)30 FrameHandler::FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
31                            android::sp <IEvsDisplay> pDisplay,
32                            BufferControlFlag mode) :
33     mCamera(pCamera),
34     mCameraInfo(cameraInfo),
35     mDisplay(pDisplay),
36     mReturnMode(mode) {
37     // Nothing but member initialization here...
38 }
39 
40 
shutdown()41 void FrameHandler::shutdown()
42 {
43     // Make sure we're not still streaming
44     blockingStopStream();
45 
46     // At this point, the receiver thread is no longer running, so we can safely drop
47     // our remote object references so they can be freed
48     mCamera = nullptr;
49     mDisplay = nullptr;
50 }
51 
52 
startStream()53 bool FrameHandler::startStream() {
54     // Tell the camera to start streaming
55     Return<EvsResult> result = mCamera->startVideoStream(this);
56     if (result != EvsResult::OK) {
57         return false;
58     }
59 
60     // Mark ourselves as running
61     mLock.lock();
62     mRunning = true;
63     mLock.unlock();
64 
65     return true;
66 }
67 
68 
asyncStopStream()69 void FrameHandler::asyncStopStream() {
70     // Tell the camera to stop streaming.
71     // This will result in a null frame being delivered when the stream actually stops.
72     mCamera->stopVideoStream();
73 }
74 
75 
blockingStopStream()76 void FrameHandler::blockingStopStream() {
77     // Tell the stream to stop
78     asyncStopStream();
79 
80     // Wait until the stream has actually stopped
81     std::unique_lock<std::mutex> lock(mLock);
82     if (mRunning) {
83         mSignal.wait(lock, [this]() { return !mRunning; });
84     }
85 }
86 
87 
returnHeldBuffer()88 bool FrameHandler::returnHeldBuffer() {
89     std::unique_lock<std::mutex> lock(mLock);
90 
91     // Return the oldest buffer we're holding
92     if (mHeldBuffers.empty()) {
93         // No buffers are currently held
94         return false;
95     }
96 
97     BufferDesc buffer = mHeldBuffers.front();
98     mHeldBuffers.pop();
99     mCamera->doneWithFrame(buffer);
100 
101     return true;
102 }
103 
104 
isRunning()105 bool FrameHandler::isRunning() {
106     std::unique_lock<std::mutex> lock(mLock);
107     return mRunning;
108 }
109 
110 
waitForFrameCount(unsigned frameCount)111 void FrameHandler::waitForFrameCount(unsigned frameCount) {
112     // Wait until we've seen at least the requested number of frames (could be more)
113     std::unique_lock<std::mutex> lock(mLock);
114     mSignal.wait(lock, [this, frameCount](){ return mFramesReceived >= frameCount; });
115 }
116 
117 
getFramesCounters(unsigned * received,unsigned * displayed)118 void FrameHandler::getFramesCounters(unsigned* received, unsigned* displayed) {
119     std::unique_lock<std::mutex> lock(mLock);
120 
121     if (received) {
122         *received = mFramesReceived;
123     }
124     if (displayed) {
125         *displayed = mFramesDisplayed;
126     }
127 }
128 
129 
deliverFrame(const BufferDesc & bufferArg)130 Return<void> FrameHandler::deliverFrame(const BufferDesc& bufferArg) {
131     ALOGD("Received a frame from the camera (%p)", bufferArg.memHandle.getNativeHandle());
132 
133     // Local flag we use to keep track of when the stream is stopping
134     bool timeToStop = false;
135 
136     if (bufferArg.memHandle.getNativeHandle() == nullptr) {
137         // Signal that the last frame has been received and the stream is stopped
138         timeToStop = true;
139     } else {
140         // If we were given an opened display at construction time, then send the received
141         // image back down the camera.
142         if (mDisplay.get()) {
143             // Get the output buffer we'll use to display the imagery
144             BufferDesc tgtBuffer = {};
145             mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc& buff) {
146                                           tgtBuffer = buff;
147                                       }
148             );
149 
150             if (tgtBuffer.memHandle == nullptr) {
151                 printf("Didn't get target buffer - frame lost\n");
152                 ALOGE("Didn't get requested output buffer -- skipping this frame.");
153             } else {
154                 // Copy the contents of the of buffer.memHandle into tgtBuffer
155                 copyBufferContents(tgtBuffer, bufferArg);
156 
157                 // Send the target buffer back for display
158                 Return <EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
159                 if (!result.isOk()) {
160                     printf("HIDL error on display buffer (%s)- frame lost\n",
161                            result.description().c_str());
162                     ALOGE("Error making the remote function call.  HIDL said %s",
163                           result.description().c_str());
164                 } else if (result != EvsResult::OK) {
165                     printf("Display reported error - frame lost\n");
166                     ALOGE("We encountered error %d when returning a buffer to the display!",
167                           (EvsResult) result);
168                 } else {
169                     // Everything looks good!
170                     // Keep track so tests or watch dogs can monitor progress
171                     mLock.lock();
172                     mFramesDisplayed++;
173                     mLock.unlock();
174                 }
175             }
176         }
177 
178 
179         switch (mReturnMode) {
180         case eAutoReturn:
181             // Send the camera buffer back now that the client has seen it
182             ALOGD("Calling doneWithFrame");
183             // TODO:  Why is it that we get a HIDL crash if we pass back the cloned buffer?
184             mCamera->doneWithFrame(bufferArg);
185             break;
186         case eNoAutoReturn:
187             // Hang onto the buffer handle for now -- the client will return it explicitly later
188             mHeldBuffers.push(bufferArg);
189         }
190 
191 
192         ALOGD("Frame handling complete");
193     }
194 
195 
196     // Update our received frame count and notify anybody who cares that things have changed
197     mLock.lock();
198     if (timeToStop) {
199         mRunning = false;
200     } else {
201         mFramesReceived++;
202     }
203     mLock.unlock();
204     mSignal.notify_all();
205 
206 
207     return Void();
208 }
209 
210 
copyBufferContents(const BufferDesc & tgtBuffer,const BufferDesc & srcBuffer)211 bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer,
212                                       const BufferDesc& srcBuffer) {
213     bool success = true;
214 
215     // Make sure we don't run off the end of either buffer
216     const unsigned width     = std::min(tgtBuffer.width,
217                                         srcBuffer.width);
218     const unsigned height    = std::min(tgtBuffer.height,
219                                         srcBuffer.height);
220 
221     sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(
222         tgtBuffer.memHandle, android::GraphicBuffer::CLONE_HANDLE,
223         tgtBuffer.width, tgtBuffer.height, tgtBuffer.format, 1, tgtBuffer.usage,
224         tgtBuffer.stride);
225     sp<android::GraphicBuffer> src = new android::GraphicBuffer(
226         srcBuffer.memHandle, android::GraphicBuffer::CLONE_HANDLE,
227         srcBuffer.width, srcBuffer.height, srcBuffer.format, 1, srcBuffer.usage,
228         srcBuffer.stride);
229 
230     // Lock our source buffer for reading (current expectation are for this to be NV21 format)
231     uint8_t* srcPixels = nullptr;
232     src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
233 
234     // Lock our target buffer for writing (should be RGBA8888 format)
235     uint32_t* tgtPixels = nullptr;
236     tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
237 
238     if (srcPixels && tgtPixels) {
239         if (tgtBuffer.format != HAL_PIXEL_FORMAT_RGBA_8888) {
240             // We always expect 32 bit RGB for the display output for now.  Is there a need for 565?
241             ALOGE("Diplay buffer is always expected to be 32bit RGBA");
242             success = false;
243         } else {
244             if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) {   // 420SP == NV21
245                 copyNV21toRGB32(width, height,
246                                 srcPixels,
247                                 tgtPixels, tgtBuffer.stride);
248             } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
249                 copyYV12toRGB32(width, height,
250                                 srcPixels,
251                                 tgtPixels, tgtBuffer.stride);
252             } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
253                 copyYUYVtoRGB32(width, height,
254                                 srcPixels, srcBuffer.stride,
255                                 tgtPixels, tgtBuffer.stride);
256             } else if (srcBuffer.format == tgtBuffer.format) {  // 32bit RGBA
257                 copyMatchedInterleavedFormats(width, height,
258                                               srcPixels, srcBuffer.stride,
259                                               tgtPixels, tgtBuffer.stride,
260                                               tgtBuffer.pixelSize);
261             }
262         }
263     } else {
264         ALOGE("Failed to lock buffer contents for contents transfer");
265         success = false;
266     }
267 
268     if (srcPixels) {
269         src->unlock();
270     }
271     if (tgtPixels) {
272         tgt->unlock();
273     }
274 
275     return success;
276 }
277