1 /* 2 * Copyright (C) 2012 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 #ifndef __ANDROID_HAL_CAMERA2_TESTS_STREAM_FIXTURE__ 18 #define __ANDROID_HAL_CAMERA2_TESTS_STREAM_FIXTURE__ 19 20 #include <gtest/gtest.h> 21 #include <iostream> 22 #include <fstream> 23 24 #include <gui/CpuConsumer.h> 25 #include <gui/Surface.h> 26 #include <utils/Condition.h> 27 #include <utils/Mutex.h> 28 #include <system/camera_metadata.h> 29 30 #include "CameraModuleFixture.h" 31 #include "TestExtensions.h" 32 33 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) 34 35 namespace android { 36 namespace camera2 { 37 namespace tests { 38 39 // Format specifier for picking the best format for CPU reading the given device 40 // version 41 #define CAMERA_STREAM_AUTO_CPU_FORMAT (-1) 42 43 struct CameraStreamParams; 44 45 void PrintTo(const CameraStreamParams& p, ::std::ostream* os); 46 47 struct CameraStreamParams { 48 int mFormat; 49 int mHeapCount; 50 51 }; 52 53 inline ::std::ostream& operator<<(::std::ostream& os, const CameraStreamParams &p) { 54 PrintTo(p, &os); 55 return os; 56 } 57 58 inline void PrintTo(const CameraStreamParams& p, ::std::ostream* os) { 59 char fmt[100]; 60 camera_metadata_enum_snprint( 61 ANDROID_SCALER_AVAILABLE_FORMATS, p.mFormat, fmt, sizeof(fmt)); 62 63 *os << "{ "; 64 *os << "Format: 0x" << std::hex << p.mFormat << ", "; 65 *os << "Format name: " << fmt << ", "; 66 *os << "HeapCount: " << p.mHeapCount; 67 *os << " }"; 68 } 69 70 class CameraStreamFixture 71 : public CameraModuleFixture</*InfoQuirk*/true> { 72 73 public: 74 CameraStreamFixture(CameraStreamParams p) 75 : CameraModuleFixture(TestSettings::DeviceId()) { 76 TEST_EXTENSION_FORKING_CONSTRUCTOR; 77 78 mParam = p; 79 80 SetUp(); 81 } 82 83 ~CameraStreamFixture() { 84 TEST_EXTENSION_FORKING_DESTRUCTOR; 85 86 TearDown(); 87 } 88 89 private: 90 91 void SetUp() { 92 TEST_EXTENSION_FORKING_SET_UP; 93 94 CameraModuleFixture::SetUp(); 95 96 sp<CameraDeviceBase> device = mDevice; 97 98 /* use an arbitrary w,h */ 99 if (getDeviceVersion() < CAMERA_DEVICE_API_VERSION_3_2) { 100 const int tag = ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES; 101 102 const CameraMetadata& staticInfo = device->info(); 103 camera_metadata_ro_entry entry = staticInfo.find(tag); 104 ASSERT_NE(0u, entry.count) 105 << "Missing tag android.scaler.availableProcessedSizes"; 106 107 ASSERT_LE(2u, entry.count); 108 /* this seems like it would always be the smallest w,h 109 but we actually make no contract that it's sorted asc */ 110 mWidth = entry.data.i32[0]; 111 mHeight = entry.data.i32[1]; 112 } else { 113 buildOutputResolutions(); 114 const int32_t *implDefResolutions = NULL; 115 size_t implDefResolutionsCount; 116 117 int format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; 118 119 getResolutionList(format, 120 &implDefResolutions, &implDefResolutionsCount); 121 ASSERT_NE(0u, implDefResolutionsCount) 122 << "Missing implementation defined sizes"; 123 mWidth = implDefResolutions[0]; 124 mHeight = implDefResolutions[1]; 125 } 126 } 127 void TearDown() { 128 TEST_EXTENSION_FORKING_TEAR_DOWN; 129 130 // important: shut down HAL before releasing streams 131 CameraModuleFixture::TearDown(); 132 133 deleteOutputResolutions(); 134 mSurface.clear(); 135 mCpuConsumer.clear(); 136 mFrameListener.clear(); 137 } 138 139 protected: 140 141 int64_t getMinFrameDurationFor(int32_t format, int32_t width, int32_t height) { 142 int64_t minFrameDuration = -1L; 143 const int tag = ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS; 144 sp<CameraDeviceBase> device = mDevice; 145 const CameraMetadata& staticInfo = device->info(); 146 camera_metadata_ro_entry_t availableMinDurations = staticInfo.find(tag); 147 for (uint32_t i = 0; i < availableMinDurations.count; i += 4) { 148 if (format == availableMinDurations.data.i64[i] && 149 width == availableMinDurations.data.i64[i + 1] && 150 height == availableMinDurations.data.i64[i + 2]) { 151 minFrameDuration = availableMinDurations.data.i64[i + 3]; 152 break; 153 } 154 } 155 return minFrameDuration; 156 } 157 158 void buildOutputResolutions() { 159 if (getDeviceVersion() < CAMERA_DEVICE_API_VERSION_3_2) { 160 return; 161 } 162 if (mOutputResolutions.isEmpty()) { 163 const int tag = ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS; 164 const CameraMetadata& staticInfo = mDevice->info(); 165 camera_metadata_ro_entry_t availableStrmConfigs = staticInfo.find(tag); 166 ASSERT_EQ(0u, availableStrmConfigs.count % 4); 167 for (uint32_t i = 0; i < availableStrmConfigs.count; i += 4) { 168 int32_t format = availableStrmConfigs.data.i32[i]; 169 int32_t width = availableStrmConfigs.data.i32[i + 1]; 170 int32_t height = availableStrmConfigs.data.i32[i + 2]; 171 int32_t inOrOut = availableStrmConfigs.data.i32[i + 3]; 172 if (inOrOut == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) { 173 int index = mOutputResolutions.indexOfKey(format); 174 if (index < 0) { 175 index = mOutputResolutions.add(format, new Vector<int32_t>()); 176 ASSERT_TRUE(index >= 0); 177 } 178 Vector<int32_t> *resolutions = mOutputResolutions.editValueAt(index); 179 resolutions->add(width); 180 resolutions->add(height); 181 } 182 } 183 } 184 } 185 186 void getResolutionList(int32_t format, 187 const int32_t **list, 188 size_t *count) { 189 ALOGV("Getting resolutions for format %x", format); 190 if (getDeviceVersion() < CAMERA_DEVICE_API_VERSION_3_2) { 191 return; 192 } 193 int index = mOutputResolutions.indexOfKey(format); 194 ASSERT_TRUE(index >= 0); 195 Vector<int32_t>* resolutions = mOutputResolutions.valueAt(index); 196 *list = resolutions->array(); 197 *count = resolutions->size(); 198 } 199 200 void deleteOutputResolutions() { 201 for (uint32_t i = 0; i < mOutputResolutions.size(); i++) { 202 Vector<int32_t>* resolutions = mOutputResolutions.editValueAt(i); 203 delete resolutions; 204 } 205 mOutputResolutions.clear(); 206 } 207 208 struct FrameListener : public ConsumerBase::FrameAvailableListener { 209 210 FrameListener() { 211 mPendingFrames = 0; 212 } 213 214 // CpuConsumer::FrameAvailableListener implementation 215 virtual void onFrameAvailable(const BufferItem& /* item */) { 216 ALOGV("Frame now available (start)"); 217 218 Mutex::Autolock lock(mMutex); 219 mPendingFrames++; 220 mCondition.signal(); 221 222 ALOGV("Frame now available (end)"); 223 } 224 225 status_t waitForFrame(nsecs_t timeout) { 226 status_t res; 227 Mutex::Autolock lock(mMutex); 228 while (mPendingFrames == 0) { 229 res = mCondition.waitRelative(mMutex, timeout); 230 if (res != OK) return res; 231 } 232 mPendingFrames--; 233 return OK; 234 } 235 236 private: 237 Mutex mMutex; 238 Condition mCondition; 239 int mPendingFrames; 240 }; 241 242 void CreateStream() { 243 sp<CameraDeviceBase> device = mDevice; 244 CameraStreamParams p = mParam; 245 246 sp<IGraphicBufferProducer> producer; 247 sp<IGraphicBufferConsumer> consumer; 248 BufferQueue::createBufferQueue(&producer, &consumer); 249 mCpuConsumer = new CpuConsumer(consumer, p.mHeapCount); 250 mCpuConsumer->setName(String8("CameraStreamTest::mCpuConsumer")); 251 252 mSurface = new Surface(producer); 253 254 int format = MapAutoFormat(p.mFormat); 255 256 ASSERT_EQ(OK, 257 device->createStream(mSurface, 258 mWidth, mHeight, format, 259 HAL_DATASPACE_UNKNOWN, 260 CAMERA3_STREAM_ROTATION_0, 261 &mStreamId)); 262 263 ASSERT_NE(-1, mStreamId); 264 265 // do not make 'this' a FrameListener or the lifetime policy will clash 266 mFrameListener = new FrameListener(); 267 mCpuConsumer->setFrameAvailableListener(mFrameListener); 268 } 269 270 void DeleteStream() { 271 ASSERT_EQ(OK, mDevice->deleteStream(mStreamId)); 272 } 273 274 int MapAutoFormat(int format) { 275 if (format == CAMERA_STREAM_AUTO_CPU_FORMAT) { 276 if (getDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_0) { 277 format = HAL_PIXEL_FORMAT_YCbCr_420_888; 278 } else { 279 format = HAL_PIXEL_FORMAT_YCrCb_420_SP; 280 } 281 } 282 return format; 283 } 284 285 void DumpYuvToFile(const String8 &fileName, const CpuConsumer::LockedBuffer &img) { 286 uint8_t *dataCb, *dataCr; 287 uint32_t stride; 288 uint32_t chromaStride; 289 uint32_t chromaStep; 290 291 switch (img.format) { 292 case HAL_PIXEL_FORMAT_YCbCr_420_888: 293 stride = img.stride; 294 chromaStride = img.chromaStride; 295 chromaStep = img.chromaStep; 296 dataCb = img.dataCb; 297 dataCr = img.dataCr; 298 break; 299 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 300 stride = img.width; 301 chromaStride = img.width; 302 chromaStep = 2; 303 dataCr = img.data + img.width * img.height; 304 dataCb = dataCr + 1; 305 break; 306 case HAL_PIXEL_FORMAT_YV12: 307 stride = img.stride; 308 chromaStride = ALIGN(img.width / 2, 16); 309 chromaStep = 1; 310 dataCr = img.data + img.stride * img.height; 311 dataCb = dataCr + chromaStride * img.height/2; 312 break; 313 default: 314 ALOGE("Unknown format %d, not dumping", img.format); 315 return; 316 } 317 318 // Write Y 319 FILE *yuvFile = fopen(fileName.string(), "w"); 320 321 size_t bytes; 322 323 for (size_t y = 0; y < img.height; ++y) { 324 bytes = fwrite( 325 reinterpret_cast<const char*>(img.data + stride * y), 326 1, img.width, yuvFile); 327 if (bytes != img.width) { 328 ALOGE("Unable to write to file %s", fileName.string()); 329 fclose(yuvFile); 330 return; 331 } 332 } 333 334 // Write Cb/Cr 335 uint8_t *src = dataCb; 336 for (int c = 0; c < 2; ++c) { 337 for (size_t y = 0; y < img.height / 2; ++y) { 338 uint8_t *px = src + y * chromaStride; 339 if (chromaStep != 1) { 340 for (size_t x = 0; x < img.width / 2; ++x) { 341 fputc(*px, yuvFile); 342 px += chromaStep; 343 } 344 } else { 345 bytes = fwrite(reinterpret_cast<const char*>(px), 346 1, img.width / 2, yuvFile); 347 if (bytes != img.width / 2) { 348 ALOGE("Unable to write to file %s", fileName.string()); 349 fclose(yuvFile); 350 return; 351 } 352 } 353 } 354 src = dataCr; 355 } 356 fclose(yuvFile); 357 } 358 359 int mWidth; 360 int mHeight; 361 362 int mStreamId; 363 364 android::sp<FrameListener> mFrameListener; 365 android::sp<CpuConsumer> mCpuConsumer; 366 android::sp<Surface> mSurface; 367 KeyedVector<int32_t, Vector<int32_t>* > mOutputResolutions; 368 369 private: 370 CameraStreamParams mParam; 371 }; 372 373 } 374 } 375 } 376 377 #endif 378