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 { 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 } 113 } 114 void TearDown() { 115 TEST_EXTENSION_FORKING_TEAR_DOWN; 116 117 // important: shut down HAL before releasing streams 118 CameraModuleFixture::TearDown(); 119 120 mNativeWindow.clear(); 121 mCpuConsumer.clear(); 122 mFrameListener.clear(); 123 } 124 125 protected: 126 struct FrameListener : public ConsumerBase::FrameAvailableListener { 127 128 FrameListener() { 129 mPendingFrames = 0; 130 } 131 132 // CpuConsumer::FrameAvailableListener implementation 133 virtual void onFrameAvailable() { 134 ALOGV("Frame now available (start)"); 135 136 Mutex::Autolock lock(mMutex); 137 mPendingFrames++; 138 mCondition.signal(); 139 140 ALOGV("Frame now available (end)"); 141 } 142 143 status_t waitForFrame(nsecs_t timeout) { 144 status_t res; 145 Mutex::Autolock lock(mMutex); 146 while (mPendingFrames == 0) { 147 res = mCondition.waitRelative(mMutex, timeout); 148 if (res != OK) return res; 149 } 150 mPendingFrames--; 151 return OK; 152 } 153 154 private: 155 Mutex mMutex; 156 Condition mCondition; 157 int mPendingFrames; 158 }; 159 160 void CreateStream() { 161 sp<CameraDeviceBase> device = mDevice; 162 CameraStreamParams p = mParam; 163 164 sp<IGraphicBufferProducer> producer; 165 sp<IGraphicBufferConsumer> consumer; 166 BufferQueue::createBufferQueue(&producer, &consumer); 167 mCpuConsumer = new CpuConsumer(consumer, p.mHeapCount); 168 mCpuConsumer->setName(String8("CameraStreamTest::mCpuConsumer")); 169 170 mNativeWindow = new Surface(producer); 171 172 int format = MapAutoFormat(p.mFormat); 173 174 ASSERT_EQ(OK, 175 device->createStream(mNativeWindow, 176 mWidth, mHeight, format, 177 &mStreamId)); 178 179 ASSERT_NE(-1, mStreamId); 180 181 // do not make 'this' a FrameListener or the lifetime policy will clash 182 mFrameListener = new FrameListener(); 183 mCpuConsumer->setFrameAvailableListener(mFrameListener); 184 } 185 186 void DeleteStream() { 187 ASSERT_EQ(OK, mDevice->deleteStream(mStreamId)); 188 } 189 190 int MapAutoFormat(int format) { 191 if (format == CAMERA_STREAM_AUTO_CPU_FORMAT) { 192 if (getDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_0) { 193 format = HAL_PIXEL_FORMAT_YCbCr_420_888; 194 } else { 195 format = HAL_PIXEL_FORMAT_YCrCb_420_SP; 196 } 197 } 198 return format; 199 } 200 201 void DumpYuvToFile(const String8 &fileName, const CpuConsumer::LockedBuffer &img) { 202 uint8_t *dataCb, *dataCr; 203 uint32_t stride; 204 uint32_t chromaStride; 205 uint32_t chromaStep; 206 207 switch (img.format) { 208 case HAL_PIXEL_FORMAT_YCbCr_420_888: 209 stride = img.stride; 210 chromaStride = img.chromaStride; 211 chromaStep = img.chromaStep; 212 dataCb = img.dataCb; 213 dataCr = img.dataCr; 214 break; 215 case HAL_PIXEL_FORMAT_YCrCb_420_SP: 216 stride = img.width; 217 chromaStride = img.width; 218 chromaStep = 2; 219 dataCr = img.data + img.width * img.height; 220 dataCb = dataCr + 1; 221 break; 222 case HAL_PIXEL_FORMAT_YV12: 223 stride = img.stride; 224 chromaStride = ALIGN(img.width / 2, 16); 225 chromaStep = 1; 226 dataCr = img.data + img.stride * img.height; 227 dataCb = dataCr + chromaStride * img.height/2; 228 break; 229 default: 230 ALOGE("Unknown format %d, not dumping", img.format); 231 return; 232 } 233 234 // Write Y 235 FILE *yuvFile = fopen(fileName.string(), "w"); 236 237 size_t bytes; 238 239 for (size_t y = 0; y < img.height; ++y) { 240 bytes = fwrite( 241 reinterpret_cast<const char*>(img.data + stride * y), 242 1, img.width, yuvFile); 243 if (bytes != img.width) { 244 ALOGE("Unable to write to file %s", fileName.string()); 245 fclose(yuvFile); 246 return; 247 } 248 } 249 250 // Write Cb/Cr 251 uint8_t *src = dataCb; 252 for (int c = 0; c < 2; ++c) { 253 for (size_t y = 0; y < img.height / 2; ++y) { 254 uint8_t *px = src + y * chromaStride; 255 if (chromaStep != 1) { 256 for (size_t x = 0; x < img.width / 2; ++x) { 257 fputc(*px, yuvFile); 258 px += chromaStep; 259 } 260 } else { 261 bytes = fwrite(reinterpret_cast<const char*>(px), 262 1, img.width / 2, yuvFile); 263 if (bytes != img.width / 2) { 264 ALOGE("Unable to write to file %s", fileName.string()); 265 fclose(yuvFile); 266 return; 267 } 268 } 269 } 270 src = dataCr; 271 } 272 fclose(yuvFile); 273 } 274 275 int mWidth; 276 int mHeight; 277 278 int mStreamId; 279 280 android::sp<FrameListener> mFrameListener; 281 android::sp<CpuConsumer> mCpuConsumer; 282 android::sp<ANativeWindow> mNativeWindow; 283 284 285 private: 286 CameraStreamParams mParam; 287 }; 288 289 } 290 } 291 } 292 293 #endif 294