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 // Store a dimension of a received frame.
141 mFrameWidth = bufferArg.width;
142 mFrameHeight = bufferArg.height;
143
144 // If we were given an opened display at construction time, then send the received
145 // image back down the camera.
146 if (mDisplay.get()) {
147 // Get the output buffer we'll use to display the imagery
148 BufferDesc tgtBuffer = {};
149 mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc& buff) {
150 tgtBuffer = buff;
151 }
152 );
153
154 if (tgtBuffer.memHandle == nullptr) {
155 printf("Didn't get target buffer - frame lost\n");
156 ALOGE("Didn't get requested output buffer -- skipping this frame.");
157 } else {
158 // Copy the contents of the of buffer.memHandle into tgtBuffer
159 copyBufferContents(tgtBuffer, bufferArg);
160
161 // Send the target buffer back for display
162 Return <EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
163 if (!result.isOk()) {
164 printf("HIDL error on display buffer (%s)- frame lost\n",
165 result.description().c_str());
166 ALOGE("Error making the remote function call. HIDL said %s",
167 result.description().c_str());
168 } else if (result != EvsResult::OK) {
169 printf("Display reported error - frame lost\n");
170 ALOGE("We encountered error %d when returning a buffer to the display!",
171 (EvsResult) result);
172 } else {
173 // Everything looks good!
174 // Keep track so tests or watch dogs can monitor progress
175 mLock.lock();
176 mFramesDisplayed++;
177 mLock.unlock();
178 }
179 }
180 }
181
182
183 switch (mReturnMode) {
184 case eAutoReturn:
185 // Send the camera buffer back now that the client has seen it
186 ALOGD("Calling doneWithFrame");
187 // TODO: Why is it that we get a HIDL crash if we pass back the cloned buffer?
188 mCamera->doneWithFrame(bufferArg);
189 break;
190 case eNoAutoReturn:
191 // Hang onto the buffer handle for now -- the client will return it explicitly later
192 mHeldBuffers.push(bufferArg);
193 }
194
195
196 ALOGD("Frame handling complete");
197 }
198
199
200 // Update our received frame count and notify anybody who cares that things have changed
201 mLock.lock();
202 if (timeToStop) {
203 mRunning = false;
204 } else {
205 mFramesReceived++;
206 }
207 mLock.unlock();
208 mSignal.notify_all();
209
210
211 return Void();
212 }
213
214
copyBufferContents(const BufferDesc & tgtBuffer,const BufferDesc & srcBuffer)215 bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer,
216 const BufferDesc& srcBuffer) {
217 bool success = true;
218
219 // Make sure we don't run off the end of either buffer
220 const unsigned width = std::min(tgtBuffer.width,
221 srcBuffer.width);
222 const unsigned height = std::min(tgtBuffer.height,
223 srcBuffer.height);
224
225 sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(
226 tgtBuffer.memHandle, android::GraphicBuffer::CLONE_HANDLE,
227 tgtBuffer.width, tgtBuffer.height, tgtBuffer.format, 1, tgtBuffer.usage,
228 tgtBuffer.stride);
229 sp<android::GraphicBuffer> src = new android::GraphicBuffer(
230 srcBuffer.memHandle, android::GraphicBuffer::CLONE_HANDLE,
231 srcBuffer.width, srcBuffer.height, srcBuffer.format, 1, srcBuffer.usage,
232 srcBuffer.stride);
233
234 // Lock our source buffer for reading (current expectation are for this to be NV21 format)
235 uint8_t* srcPixels = nullptr;
236 src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
237
238 // Lock our target buffer for writing (should be either RGBA8888 or BGRA8888 format)
239 uint32_t* tgtPixels = nullptr;
240 tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
241
242 if (srcPixels && tgtPixels) {
243 if (tgtBuffer.format == HAL_PIXEL_FORMAT_RGBA_8888) {
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 } else {
262 ALOGE("Camera buffer format is not supported");
263 success = false;
264 }
265 } else if (tgtBuffer.format == HAL_PIXEL_FORMAT_BGRA_8888) {
266 if (srcBuffer.format == HAL_PIXEL_FORMAT_YCRCB_420_SP) { // 420SP == NV21
267 copyNV21toBGR32(width, height,
268 srcPixels,
269 tgtPixels, tgtBuffer.stride);
270 } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YV12) { // YUV_420P == YV12
271 copyYV12toBGR32(width, height,
272 srcPixels,
273 tgtPixels, tgtBuffer.stride);
274 } else if (srcBuffer.format == HAL_PIXEL_FORMAT_YCBCR_422_I) { // YUYV
275 copyYUYVtoBGR32(width, height,
276 srcPixels, srcBuffer.stride,
277 tgtPixels, tgtBuffer.stride);
278 } else if (srcBuffer.format == tgtBuffer.format) { // 32bit RGBA
279 copyMatchedInterleavedFormats(width, height,
280 srcPixels, srcBuffer.stride,
281 tgtPixels, tgtBuffer.stride,
282 tgtBuffer.pixelSize);
283 } else {
284 ALOGE("Camera buffer format is not supported");
285 success = false;
286 }
287 } else {
288 // We always expect 32 bit RGB for the display output for now. Is there a need for 565?
289 ALOGE("Diplay buffer is always expected to be 32bit RGBA");
290 success = false;
291 }
292 } else {
293 ALOGE("Failed to lock buffer contents for contents transfer");
294 success = false;
295 }
296
297 if (srcPixels) {
298 src->unlock();
299 }
300 if (tgtPixels) {
301 tgt->unlock();
302 }
303
304 return success;
305 }
306
getFrameDimension(unsigned * width,unsigned * height)307 void FrameHandler::getFrameDimension(unsigned* width, unsigned* height) {
308 if (width) {
309 *width = mFrameWidth;
310 }
311
312 if (height) {
313 *height = mFrameHeight;
314 }
315 }
316