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