Home | History | Annotate | Download | only in camera2
      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