ProCameraTests.cpp revision c0767f148e29ce821281b5965c0e25b4c143e76d
1/*
2 * Copyright (C) 2013 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#include <gtest/gtest.h>
18#include <iostream>
19
20#include <binder/IPCThreadState.h>
21#include <utils/Thread.h>
22
23#include "Camera.h"
24#include "ProCamera.h"
25#include <utils/Vector.h>
26#include <utils/Mutex.h>
27#include <utils/Condition.h>
28
29#include <gui/SurfaceComposerClient.h>
30#include <gui/Surface.h>
31
32#include <system/camera_metadata.h>
33#include <hardware/camera2.h> // for CAMERA2_TEMPLATE_PREVIEW only
34
35namespace android {
36namespace camera2 {
37namespace tests {
38namespace client {
39
40#define CAMERA_ID 0
41#define TEST_DEBUGGING 0
42
43#define TEST_LISTENER_TIMEOUT 1000000000 // 1 second listener timeout
44#define TEST_FORMAT HAL_PIXEL_FORMAT_Y16 //TODO: YUY2 instead
45
46#define TEST_FORMAT_DEPTH HAL_PIXEL_FORMAT_Y16
47
48#define TEST_CPU_FRAME_COUNT 2
49#define TEST_CPU_HEAP_COUNT 5
50
51#if TEST_DEBUGGING
52#define dout std::cerr
53#else
54#define dout if (0) std::cerr
55#endif
56
57#define EXPECT_OK(x) EXPECT_EQ(OK, (x))
58#define ASSERT_OK(x) ASSERT_EQ(OK, (x))
59
60class ProCameraTest;
61
62enum ProEvent {
63    UNKNOWN,
64    ACQUIRED,
65    RELEASED,
66    STOLEN,
67    BUFFER_RECEIVED,
68};
69
70typedef Vector<ProEvent> EventList;
71
72class ProCameraTestThread : public Thread
73{
74public:
75    ProCameraTestThread() {
76    }
77
78    virtual bool threadLoop() {
79        mProc = ProcessState::self();
80        mProc->startThreadPool();
81
82        IPCThreadState *ptr = IPCThreadState::self();
83
84        ptr->joinThreadPool();
85
86        return false;
87    }
88
89    sp<ProcessState> mProc;
90};
91
92class ProCameraTestListener : public ProCameraListener {
93
94public:
95    status_t WaitForEvent() {
96        Mutex::Autolock cal(mConditionMutex);
97
98        {
99            Mutex::Autolock al(mListenerMutex);
100
101            if (mProEventList.size() > 0) {
102                return OK;
103            }
104        }
105
106        return mListenerCondition.waitRelative(mConditionMutex,
107                                               TEST_LISTENER_TIMEOUT);
108    }
109
110    /* Read events into out. Existing queue is flushed */
111    void ReadEvents(EventList& out) {
112        Mutex::Autolock al(mListenerMutex);
113
114        for (size_t i = 0; i < mProEventList.size(); ++i) {
115            out.push(mProEventList[i]);
116        }
117
118        mProEventList.clear();
119    }
120
121    /**
122      * Dequeue 1 event from the event queue.
123      * Returns UNKNOWN if queue is empty
124      */
125    ProEvent ReadEvent() {
126        Mutex::Autolock al(mListenerMutex);
127
128        if (mProEventList.size() == 0) {
129            return UNKNOWN;
130        }
131
132        ProEvent ev = mProEventList[0];
133        mProEventList.removeAt(0);
134
135        return ev;
136    }
137
138private:
139    void QueueEvent(ProEvent ev) {
140        {
141            Mutex::Autolock al(mListenerMutex);
142            mProEventList.push(ev);
143        }
144
145
146        mListenerCondition.broadcast();
147    }
148
149protected:
150
151    //////////////////////////////////////////////////
152    ///////// ProCameraListener //////////////////////
153    //////////////////////////////////////////////////
154
155
156    // Lock has been acquired. Write operations now available.
157    virtual void onLockAcquired() {
158        QueueEvent(ACQUIRED);
159    }
160    // Lock has been released with exclusiveUnlock
161    virtual void onLockReleased() {
162        QueueEvent(RELEASED);
163    }
164
165    // Lock has been stolen by another client.
166    virtual void onLockStolen() {
167        QueueEvent(STOLEN);
168    }
169
170    // Lock free.
171    virtual void onTriggerNotify(int32_t ext1, int32_t ext2, int32_t ext3) {
172
173        dout << "Trigger notify: " << ext1 << " " << ext2
174             << " " << ext3 << std::endl;
175    }
176
177    virtual void onBufferReceived(int streamId,
178                                  const CpuConsumer::LockedBuffer& buf) {
179
180        dout << "Buffer received on streamId = " << streamId <<
181                ", dataPtr = " << (void*)buf.data << std::endl;
182
183        QueueEvent(BUFFER_RECEIVED);
184
185    }
186    virtual void onRequestReceived(
187                                   camera_metadata* request) {
188        free_camera_metadata(request);
189    }
190
191    // TODO: remove
192
193    virtual void notify(int32_t , int32_t , int32_t ) {}
194    virtual void postData(int32_t , const sp<IMemory>& ,
195                          camera_frame_metadata_t *) {}
196    virtual void postDataTimestamp(nsecs_t , int32_t , const sp<IMemory>& ) {}
197
198
199    Vector<ProEvent> mProEventList;
200    Mutex             mListenerMutex;
201    Mutex             mConditionMutex;
202    Condition         mListenerCondition;
203};
204
205class ProCameraTest : public ::testing::Test {
206
207public:
208    ProCameraTest() {
209    }
210
211    static void SetUpTestCase() {
212        // Binder Thread Pool Initialization
213        mTestThread = new ProCameraTestThread();
214        mTestThread->run("ProCameraTestThread");
215    }
216
217    virtual void SetUp() {
218        mCamera = ProCamera::connect(CAMERA_ID);
219        ASSERT_NE((void*)NULL, mCamera.get());
220
221        mListener = new ProCameraTestListener();
222        mCamera->setListener(mListener);
223    }
224
225    virtual void TearDown() {
226        ASSERT_NE((void*)NULL, mCamera.get());
227        mCamera->disconnect();
228    }
229
230protected:
231    sp<ProCamera> mCamera;
232    sp<ProCameraTestListener> mListener;
233
234    static sp<Thread> mTestThread;
235
236    int mDisplaySecs;
237    sp<SurfaceComposerClient> mComposerClient;
238    sp<SurfaceControl> mSurfaceControl;
239
240    sp<SurfaceComposerClient> mDepthComposerClient;
241    sp<SurfaceControl> mDepthSurfaceControl;
242
243    int getSurfaceWidth() {
244        return 512;
245    }
246    int getSurfaceHeight() {
247        return 512;
248    }
249
250    void createOnScreenSurface(sp<Surface>& surface) {
251        mComposerClient = new SurfaceComposerClient;
252        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
253
254        mSurfaceControl = mComposerClient->createSurface(
255                String8("ProCameraTest StreamingImage Surface"),
256                getSurfaceWidth(), getSurfaceHeight(),
257                PIXEL_FORMAT_RGB_888, 0);
258
259        mSurfaceControl->setPosition(640, 0);
260
261        ASSERT_TRUE(mSurfaceControl != NULL);
262        ASSERT_TRUE(mSurfaceControl->isValid());
263
264        SurfaceComposerClient::openGlobalTransaction();
265        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
266        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
267        SurfaceComposerClient::closeGlobalTransaction();
268
269        sp<ANativeWindow> window = mSurfaceControl->getSurface();
270        surface = mSurfaceControl->getSurface();
271
272        ASSERT_NE((void*)NULL, surface.get());
273    }
274
275    void createDepthOnScreenSurface(sp<Surface>& surface) {
276        mDepthComposerClient = new SurfaceComposerClient;
277        ASSERT_EQ(NO_ERROR, mDepthComposerClient->initCheck());
278
279        mDepthSurfaceControl = mDepthComposerClient->createSurface(
280                String8("ProCameraTest StreamingImage Surface"),
281                getSurfaceWidth(), getSurfaceHeight(),
282                PIXEL_FORMAT_RGB_888, 0);
283
284        mDepthSurfaceControl->setPosition(640, 0);
285
286        ASSERT_TRUE(mDepthSurfaceControl != NULL);
287        ASSERT_TRUE(mDepthSurfaceControl->isValid());
288
289        SurfaceComposerClient::openGlobalTransaction();
290        ASSERT_EQ(NO_ERROR, mDepthSurfaceControl->setLayer(0x7FFFFFFF));
291        ASSERT_EQ(NO_ERROR, mDepthSurfaceControl->show());
292        SurfaceComposerClient::closeGlobalTransaction();
293
294        sp<ANativeWindow> window = mDepthSurfaceControl->getSurface();
295        surface = mDepthSurfaceControl->getSurface();
296
297        ASSERT_NE((void*)NULL, surface.get());
298    }
299
300};
301
302sp<Thread> ProCameraTest::mTestThread;
303
304// test around exclusiveTryLock (immediate locking)
305TEST_F(ProCameraTest, LockingImmediate) {
306
307    if (HasFatalFailure()) {
308        return;
309    }
310
311    EXPECT_FALSE(mCamera->hasExclusiveLock());
312    EXPECT_EQ(OK, mCamera->exclusiveTryLock());
313    // at this point we definitely have the lock
314
315    EXPECT_EQ(OK, mListener->WaitForEvent());
316    EXPECT_EQ(ACQUIRED, mListener->ReadEvent());
317
318    EXPECT_TRUE(mCamera->hasExclusiveLock());
319    EXPECT_EQ(OK, mCamera->exclusiveUnlock());
320
321    EXPECT_EQ(OK, mListener->WaitForEvent());
322    EXPECT_EQ(RELEASED, mListener->ReadEvent());
323
324    EXPECT_FALSE(mCamera->hasExclusiveLock());
325}
326
327// test around exclusiveLock (locking at some future point in time)
328TEST_F(ProCameraTest, LockingAsynchronous) {
329
330    if (HasFatalFailure()) {
331        return;
332    }
333
334    // TODO: Add another procamera that has a lock here.
335    // then we can be test that the lock wont immediately be acquired
336
337    EXPECT_FALSE(mCamera->hasExclusiveLock());
338    EXPECT_EQ(OK, mCamera->exclusiveLock());
339    // at this point we may or may not have the lock
340    // we cant be sure until we get an ACQUIRED event
341
342    EXPECT_EQ(OK, mListener->WaitForEvent());
343    EXPECT_EQ(ACQUIRED, mListener->ReadEvent());
344
345    EXPECT_TRUE(mCamera->hasExclusiveLock());
346    EXPECT_EQ(OK, mCamera->exclusiveUnlock());
347
348    EXPECT_EQ(OK, mListener->WaitForEvent());
349    EXPECT_EQ(RELEASED, mListener->ReadEvent());
350
351    EXPECT_FALSE(mCamera->hasExclusiveLock());
352}
353
354// Stream directly to the screen.
355TEST_F(ProCameraTest, StreamingImage) {
356    if (HasFatalFailure()) {
357        return;
358    }
359    char* displaySecsEnv = getenv("TEST_DISPLAY_SECS");
360    if (displaySecsEnv != NULL) {
361        mDisplaySecs = atoi(displaySecsEnv);
362        if (mDisplaySecs < 0) {
363            mDisplaySecs = 0;
364        }
365    } else {
366        mDisplaySecs = 0;
367    }
368
369    sp<Surface> depthSurface;
370    if (mDisplaySecs > 0) {
371        createDepthOnScreenSurface(/*out*/depthSurface);
372    }
373
374    int depthStreamId = -1;
375    EXPECT_OK(mCamera->createStream(/*width*/320, /*height*/240,
376                              TEST_FORMAT_DEPTH, depthSurface, &depthStreamId));
377    EXPECT_NE(-1, depthStreamId);
378
379    EXPECT_OK(mCamera->exclusiveTryLock());
380    /* iterate in a loop submitting requests every frame.
381     *  what kind of requests doesnt really matter, just whatever.
382     */
383
384    // it would probably be better to use CameraMetadata from camera service.
385    camera_metadata_t *request = NULL;
386    EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
387              /*out*/&request));
388    EXPECT_NE((void*)NULL, request);
389
390    /* FIXME: dont need this later, at which point the above should become an
391       ASSERT_NE*/
392    if(request == NULL) request = allocate_camera_metadata(10, 100);
393
394    // set the output streams to just this stream ID
395
396    // wow what a verbose API.
397    // i would give a loaf of bread for
398    //   metadata->updateOrInsert(keys.request.output.streams, streamId);
399    uint8_t allStreams[] = { depthStreamId };
400    size_t streamCount = sizeof(allStreams) / sizeof(allStreams[0]);
401
402    camera_metadata_entry_t entry;
403    uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS);
404    int find = find_camera_metadata_entry(request, tag, &entry);
405    if (find == -ENOENT) {
406        if (add_camera_metadata_entry(request, tag, &allStreams,
407            /*data_count*/streamCount) != OK) {
408            camera_metadata_t *tmp = allocate_camera_metadata(1000, 10000);
409            ASSERT_OK(append_camera_metadata(tmp, request));
410            free_camera_metadata(request);
411            request = tmp;
412
413            ASSERT_OK(add_camera_metadata_entry(request, tag, &allStreams,
414                /*data_count*/streamCount));
415        }
416    } else {
417        ASSERT_OK(update_camera_metadata_entry(request, entry.index,
418                &allStreams, /*data_count*/streamCount, &entry));
419    }
420
421    EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true));
422
423    dout << "will sleep now for " << mDisplaySecs << std::endl;
424    sleep(mDisplaySecs);
425
426    free_camera_metadata(request);
427
428    for (int i = 0; i < streamCount; ++i) {
429        EXPECT_OK(mCamera->deleteStream(allStreams[i]));
430    }
431    EXPECT_OK(mCamera->exclusiveUnlock());
432}
433
434TEST_F(ProCameraTest, CpuConsumer) {
435    if (HasFatalFailure()) {
436        return;
437    }
438    int streamId = -1;
439    EXPECT_OK(mCamera->createStreamCpu(/*width*/320, /*height*/240,
440        TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &streamId));
441    EXPECT_NE(-1, streamId);
442
443    EXPECT_OK(mCamera->exclusiveTryLock());
444    EXPECT_EQ(OK, mListener->WaitForEvent());
445    EXPECT_EQ(ACQUIRED, mListener->ReadEvent());
446    /* iterate in a loop submitting requests every frame.
447     *  what kind of requests doesnt really matter, just whatever.
448     */
449
450    // it would probably be better to use CameraMetadata from camera service.
451    camera_metadata_t *request = NULL;
452    EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
453        /*out*/&request));
454    EXPECT_NE((void*)NULL, request);
455
456    /*FIXME: dont need this later, at which point the above should become an
457      ASSERT_NE*/
458    if(request == NULL) request = allocate_camera_metadata(10, 100);
459
460    // set the output streams to just this stream ID
461
462    uint8_t allStreams[] = { streamId };
463    camera_metadata_entry_t entry;
464    uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS);
465    int find = find_camera_metadata_entry(request, tag, &entry);
466    if (find == -ENOENT) {
467        if (add_camera_metadata_entry(request, tag, &allStreams,
468                /*data_count*/1) != OK) {
469            camera_metadata_t *tmp = allocate_camera_metadata(1000, 10000);
470            ASSERT_OK(append_camera_metadata(tmp, request));
471            free_camera_metadata(request);
472            request = tmp;
473
474            ASSERT_OK(add_camera_metadata_entry(request, tag, &allStreams,
475                /*data_count*/1));
476        }
477    } else {
478        ASSERT_OK(update_camera_metadata_entry(request, entry.index,
479            &allStreams, /*data_count*/1, &entry));
480    }
481
482    EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true));
483
484    // Consume a couple of frames
485    for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) {
486        EXPECT_EQ(OK, mListener->WaitForEvent());
487        EXPECT_EQ(BUFFER_RECEIVED, mListener->ReadEvent());
488    }
489
490    // Done: clean up
491    free_camera_metadata(request);
492    EXPECT_OK(mCamera->deleteStream(streamId));
493    EXPECT_OK(mCamera->exclusiveUnlock());
494}
495
496}
497}
498}
499}
500
501