1/*
2 * Copyright (C) 2011 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_NDEBUG 0
18#define LOG_TAG "SurfaceMediaSource_test"
19
20#include <gtest/gtest.h>
21#include <utils/String8.h>
22#include <utils/String16.h>
23#include <utils/Errors.h>
24#include <fcntl.h>
25#include <unistd.h>
26
27#include <GLES2/gl2.h>
28
29#include <media/stagefright/SurfaceMediaSource.h>
30#include <media/mediarecorder.h>
31
32#include <ui/GraphicBuffer.h>
33#include <gui/Surface.h>
34#include <gui/ISurfaceComposer.h>
35#include <gui/Surface.h>
36#include <gui/SurfaceComposerClient.h>
37
38#include <binder/ProcessState.h>
39
40#include <media/stagefright/foundation/ADebug.h>
41#include <OMX_Component.h>
42
43#include "DummyRecorder.h"
44
45
46namespace android {
47
48class GLTest : public ::testing::Test {
49protected:
50
51    GLTest():
52            mEglDisplay(EGL_NO_DISPLAY),
53            mEglSurface(EGL_NO_SURFACE),
54            mEglContext(EGL_NO_CONTEXT) {
55    }
56
57    virtual void SetUp() {
58        ALOGV("GLTest::SetUp()");
59        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
60        ASSERT_EQ(EGL_SUCCESS, eglGetError());
61        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
62
63        EGLint majorVersion;
64        EGLint minorVersion;
65        EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
66        ASSERT_EQ(EGL_SUCCESS, eglGetError());
67        RecordProperty("EglVersionMajor", majorVersion);
68        RecordProperty("EglVersionMajor", minorVersion);
69
70        EGLint numConfigs = 0;
71        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig,
72                1, &numConfigs));
73        ASSERT_EQ(EGL_SUCCESS, eglGetError());
74
75        char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
76        if (displaySecsEnv != NULL) {
77            mDisplaySecs = atoi(displaySecsEnv);
78            if (mDisplaySecs < 0) {
79                mDisplaySecs = 0;
80            }
81        } else {
82            mDisplaySecs = 0;
83        }
84
85        if (mDisplaySecs > 0) {
86            mComposerClient = new SurfaceComposerClient;
87            ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
88
89            mSurfaceControl = mComposerClient->createSurface(
90                    String8("Test Surface"),
91                    getSurfaceWidth(), getSurfaceHeight(),
92                    PIXEL_FORMAT_RGB_888, 0);
93
94            ASSERT_TRUE(mSurfaceControl != NULL);
95            ASSERT_TRUE(mSurfaceControl->isValid());
96
97            SurfaceComposerClient::openGlobalTransaction();
98            ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
99            ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
100            SurfaceComposerClient::closeGlobalTransaction();
101
102            sp<ANativeWindow> window = mSurfaceControl->getSurface();
103            mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
104                    window.get(), NULL);
105        } else {
106            ALOGV("No actual display. Choosing EGLSurface based on SurfaceMediaSource");
107            sp<IGraphicBufferProducer> sms = (new SurfaceMediaSource(
108                    getSurfaceWidth(), getSurfaceHeight()))->getProducer();
109            sp<Surface> stc = new Surface(sms);
110            sp<ANativeWindow> window = stc;
111
112            mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
113                    window.get(), NULL);
114        }
115        ASSERT_EQ(EGL_SUCCESS, eglGetError());
116        ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
117
118        mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT,
119                getContextAttribs());
120        ASSERT_EQ(EGL_SUCCESS, eglGetError());
121        ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
122
123        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
124                mEglContext));
125        ASSERT_EQ(EGL_SUCCESS, eglGetError());
126
127        EGLint w, h;
128        EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w));
129        ASSERT_EQ(EGL_SUCCESS, eglGetError());
130        EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h));
131        ASSERT_EQ(EGL_SUCCESS, eglGetError());
132        RecordProperty("EglSurfaceWidth", w);
133        RecordProperty("EglSurfaceHeight", h);
134
135        glViewport(0, 0, w, h);
136        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
137    }
138
139    virtual void TearDown() {
140        // Display the result
141        if (mDisplaySecs > 0 && mEglSurface != EGL_NO_SURFACE) {
142            eglSwapBuffers(mEglDisplay, mEglSurface);
143            sleep(mDisplaySecs);
144        }
145
146        if (mComposerClient != NULL) {
147            mComposerClient->dispose();
148        }
149        if (mEglContext != EGL_NO_CONTEXT) {
150            eglDestroyContext(mEglDisplay, mEglContext);
151        }
152        if (mEglSurface != EGL_NO_SURFACE) {
153            eglDestroySurface(mEglDisplay, mEglSurface);
154        }
155        if (mEglDisplay != EGL_NO_DISPLAY) {
156            eglTerminate(mEglDisplay);
157        }
158        ASSERT_EQ(EGL_SUCCESS, eglGetError());
159    }
160
161    virtual EGLint const* getConfigAttribs() {
162        ALOGV("GLTest getConfigAttribs");
163        static EGLint sDefaultConfigAttribs[] = {
164            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
165            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
166            EGL_RED_SIZE, 8,
167            EGL_GREEN_SIZE, 8,
168            EGL_BLUE_SIZE, 8,
169            EGL_ALPHA_SIZE, 8,
170            EGL_DEPTH_SIZE, 16,
171            EGL_STENCIL_SIZE, 8,
172            EGL_NONE };
173
174        return sDefaultConfigAttribs;
175    }
176
177    virtual EGLint const* getContextAttribs() {
178        static EGLint sDefaultContextAttribs[] = {
179            EGL_CONTEXT_CLIENT_VERSION, 2,
180            EGL_NONE };
181
182        return sDefaultContextAttribs;
183    }
184
185    virtual EGLint getSurfaceWidth() {
186        return 512;
187    }
188
189    virtual EGLint getSurfaceHeight() {
190        return 512;
191    }
192
193    void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
194        GLuint shader = glCreateShader(shaderType);
195        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
196        if (shader) {
197            glShaderSource(shader, 1, &pSource, NULL);
198            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
199            glCompileShader(shader);
200            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
201            GLint compiled = 0;
202            glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
203            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
204            if (!compiled) {
205                GLint infoLen = 0;
206                glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
207                ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
208                if (infoLen) {
209                    char* buf = (char*) malloc(infoLen);
210                    if (buf) {
211                        glGetShaderInfoLog(shader, infoLen, NULL, buf);
212                        printf("Shader compile log:\n%s\n", buf);
213                        free(buf);
214                        FAIL();
215                    }
216                } else {
217                    char* buf = (char*) malloc(0x1000);
218                    if (buf) {
219                        glGetShaderInfoLog(shader, 0x1000, NULL, buf);
220                        printf("Shader compile log:\n%s\n", buf);
221                        free(buf);
222                        FAIL();
223                    }
224                }
225                glDeleteShader(shader);
226                shader = 0;
227            }
228        }
229        ASSERT_TRUE(shader != 0);
230        *outShader = shader;
231    }
232
233    void createProgram(const char* pVertexSource, const char* pFragmentSource,
234            GLuint* outPgm) {
235        GLuint vertexShader, fragmentShader;
236        {
237            SCOPED_TRACE("compiling vertex shader");
238            loadShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
239            if (HasFatalFailure()) {
240                return;
241            }
242        }
243        {
244            SCOPED_TRACE("compiling fragment shader");
245            loadShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
246            if (HasFatalFailure()) {
247                return;
248            }
249        }
250
251        GLuint program = glCreateProgram();
252        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
253        if (program) {
254            glAttachShader(program, vertexShader);
255            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
256            glAttachShader(program, fragmentShader);
257            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
258            glLinkProgram(program);
259            GLint linkStatus = GL_FALSE;
260            glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
261            if (linkStatus != GL_TRUE) {
262                GLint bufLength = 0;
263                glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
264                if (bufLength) {
265                    char* buf = (char*) malloc(bufLength);
266                    if (buf) {
267                        glGetProgramInfoLog(program, bufLength, NULL, buf);
268                        printf("Program link log:\n%s\n", buf);
269                        free(buf);
270                        FAIL();
271                    }
272                }
273                glDeleteProgram(program);
274                program = 0;
275            }
276        }
277        glDeleteShader(vertexShader);
278        glDeleteShader(fragmentShader);
279        ASSERT_TRUE(program != 0);
280        *outPgm = program;
281    }
282
283    static int abs(int value) {
284        return value > 0 ? value : -value;
285    }
286
287    ::testing::AssertionResult checkPixel(int x, int y, int r,
288            int g, int b, int a, int tolerance=2) {
289        GLubyte pixel[4];
290        String8 msg;
291        glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
292        GLenum err = glGetError();
293        if (err != GL_NO_ERROR) {
294            msg += String8::format("error reading pixel: %#x", err);
295            while ((err = glGetError()) != GL_NO_ERROR) {
296                msg += String8::format(", %#x", err);
297            }
298            fprintf(stderr, "pixel check failure: %s\n", msg.string());
299            return ::testing::AssertionFailure(
300                    ::testing::Message(msg.string()));
301        }
302        if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
303            msg += String8::format("r(%d isn't %d)", pixel[0], r);
304        }
305        if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
306            if (!msg.isEmpty()) {
307                msg += " ";
308            }
309            msg += String8::format("g(%d isn't %d)", pixel[1], g);
310        }
311        if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
312            if (!msg.isEmpty()) {
313                msg += " ";
314            }
315            msg += String8::format("b(%d isn't %d)", pixel[2], b);
316        }
317        if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
318            if (!msg.isEmpty()) {
319                msg += " ";
320            }
321            msg += String8::format("a(%d isn't %d)", pixel[3], a);
322        }
323        if (!msg.isEmpty()) {
324            fprintf(stderr, "pixel check failure: %s\n", msg.string());
325            return ::testing::AssertionFailure(
326                    ::testing::Message(msg.string()));
327        } else {
328            return ::testing::AssertionSuccess();
329        }
330    }
331
332    int mDisplaySecs;
333    sp<SurfaceComposerClient> mComposerClient;
334    sp<SurfaceControl> mSurfaceControl;
335
336    EGLDisplay mEglDisplay;
337    EGLSurface mEglSurface;
338    EGLContext mEglContext;
339    EGLConfig  mGlConfig;
340};
341
342///////////////////////////////////////////////////////////////////////
343//    Class for  the NON-GL tests
344///////////////////////////////////////////////////////////////////////
345class SurfaceMediaSourceTest : public ::testing::Test {
346public:
347
348    SurfaceMediaSourceTest( ): mYuvTexWidth(176), mYuvTexHeight(144) { }
349    void oneBufferPass(int width, int height );
350    void oneBufferPassNoFill(int width, int height );
351    static void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) ;
352    static void fillYV12BufferRect(uint8_t* buf, int w, int h,
353                        int stride, const android_native_rect_t& rect) ;
354protected:
355
356    virtual void SetUp() {
357        android::ProcessState::self()->startThreadPool();
358        mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
359        mSTC = new Surface(mSMS->getProducer());
360        mANW = mSTC;
361    }
362
363    virtual void TearDown() {
364        mSMS.clear();
365        mSTC.clear();
366        mANW.clear();
367    }
368
369    const int mYuvTexWidth;
370    const int mYuvTexHeight;
371
372    sp<SurfaceMediaSource> mSMS;
373    sp<Surface> mSTC;
374    sp<ANativeWindow> mANW;
375};
376
377///////////////////////////////////////////////////////////////////////
378//    Class for  the GL tests
379///////////////////////////////////////////////////////////////////////
380class SurfaceMediaSourceGLTest : public GLTest {
381public:
382
383    SurfaceMediaSourceGLTest( ): mYuvTexWidth(176), mYuvTexHeight(144) { }
384    virtual EGLint const* getConfigAttribs();
385    void oneBufferPassGL(int num = 0);
386    static sp<MediaRecorder> setUpMediaRecorder(int fileDescriptor, int videoSource,
387        int outputFormat, int videoEncoder, int width, int height, int fps);
388protected:
389
390    virtual void SetUp() {
391        ALOGV("SMS-GLTest::SetUp()");
392        android::ProcessState::self()->startThreadPool();
393        mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
394        mSTC = new Surface(mSMS->getProducer());
395        mANW = mSTC;
396
397        // Doing the setup related to the GL Side
398        GLTest::SetUp();
399    }
400
401    virtual void TearDown() {
402        mSMS.clear();
403        mSTC.clear();
404        mANW.clear();
405        GLTest::TearDown();
406    }
407
408    void setUpEGLSurfaceFromMediaRecorder(sp<MediaRecorder>& mr);
409
410    const int mYuvTexWidth;
411    const int mYuvTexHeight;
412
413    sp<SurfaceMediaSource> mSMS;
414    sp<Surface> mSTC;
415    sp<ANativeWindow> mANW;
416};
417
418/////////////////////////////////////////////////////////////////////
419// Methods in SurfaceMediaSourceGLTest
420/////////////////////////////////////////////////////////////////////
421EGLint const* SurfaceMediaSourceGLTest::getConfigAttribs() {
422        ALOGV("SurfaceMediaSourceGLTest getConfigAttribs");
423    static EGLint sDefaultConfigAttribs[] = {
424        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
425        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
426        EGL_RED_SIZE, 8,
427        EGL_GREEN_SIZE, 8,
428        EGL_BLUE_SIZE, 8,
429        EGL_RECORDABLE_ANDROID, EGL_TRUE,
430        EGL_NONE };
431
432    return sDefaultConfigAttribs;
433}
434
435// One pass of dequeuing and queuing a GLBuffer
436void SurfaceMediaSourceGLTest::oneBufferPassGL(int num) {
437    int d = num % 50;
438    float f = 0.2f; // 0.1f * d;
439
440    glClearColor(0, 0.3, 0, 0.6);
441    glClear(GL_COLOR_BUFFER_BIT);
442
443    glEnable(GL_SCISSOR_TEST);
444    glScissor(4 + d, 4 + d, 4, 4);
445    glClearColor(1.0 - f, f, f, 1.0);
446    glClear(GL_COLOR_BUFFER_BIT);
447
448    glScissor(24 + d, 48 + d, 4, 4);
449    glClearColor(f, 1.0 - f, f, 1.0);
450    glClear(GL_COLOR_BUFFER_BIT);
451
452    glScissor(37 + d, 17 + d, 4, 4);
453    glClearColor(f, f, 1.0 - f, 1.0);
454    glClear(GL_COLOR_BUFFER_BIT);
455
456    // The following call dequeues and queues the buffer
457    eglSwapBuffers(mEglDisplay, mEglSurface);
458    ASSERT_EQ(EGL_SUCCESS, eglGetError());
459    glDisable(GL_SCISSOR_TEST);
460}
461
462// Set up the MediaRecorder which runs in the same process as mediaserver
463sp<MediaRecorder> SurfaceMediaSourceGLTest::setUpMediaRecorder(int fd, int videoSource,
464        int outputFormat, int videoEncoder, int width, int height, int fps) {
465    sp<MediaRecorder> mr = new MediaRecorder(String16());
466    mr->setVideoSource(videoSource);
467    mr->setOutputFormat(outputFormat);
468    mr->setVideoEncoder(videoEncoder);
469    mr->setOutputFile(fd, 0, 0);
470    mr->setVideoSize(width, height);
471    mr->setVideoFrameRate(fps);
472    mr->prepare();
473    ALOGV("Starting MediaRecorder...");
474    CHECK_EQ((status_t)OK, mr->start());
475    return mr;
476}
477
478// query the mediarecorder for a surfacemeidasource and create an egl surface with that
479void SurfaceMediaSourceGLTest::setUpEGLSurfaceFromMediaRecorder(sp<MediaRecorder>& mr) {
480    sp<IGraphicBufferProducer> iST = mr->querySurfaceMediaSourceFromMediaServer();
481    mSTC = new Surface(iST);
482    mANW = mSTC;
483
484    if (mEglSurface != EGL_NO_SURFACE) {
485        EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface));
486        mEglSurface = EGL_NO_SURFACE;
487    }
488    mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
489                                mANW.get(), NULL);
490    ASSERT_EQ(EGL_SUCCESS, eglGetError());
491    ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ;
492
493    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
494            mEglContext));
495    ASSERT_EQ(EGL_SUCCESS, eglGetError());
496}
497
498
499/////////////////////////////////////////////////////////////////////
500// Methods in SurfaceMediaSourceTest
501/////////////////////////////////////////////////////////////////////
502
503// One pass of dequeuing and queuing the buffer. Fill it in with
504// cpu YV12 buffer
505void SurfaceMediaSourceTest::oneBufferPass(int width, int height ) {
506    ANativeWindowBuffer* anb;
507    ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
508    ASSERT_TRUE(anb != NULL);
509
510
511    // Fill the buffer with the a checkerboard pattern
512    uint8_t* img = NULL;
513    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
514    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
515    SurfaceMediaSourceTest::fillYV12Buffer(img, width, height, buf->getStride());
516    buf->unlock();
517
518    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
519            -1));
520}
521
522// Dequeuing and queuing the buffer without really filling it in.
523void SurfaceMediaSourceTest::oneBufferPassNoFill(
524        int /* width */, int /* height  */) {
525    ANativeWindowBuffer* anb;
526    ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
527    ASSERT_TRUE(anb != NULL);
528
529    // We do not fill the buffer in. Just queue it back.
530    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
531    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
532            -1));
533}
534
535// Fill a YV12 buffer with a multi-colored checkerboard pattern
536void SurfaceMediaSourceTest::fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
537    const int blockWidth = w > 16 ? w / 16 : 1;
538    const int blockHeight = h > 16 ? h / 16 : 1;
539    const int yuvTexOffsetY = 0;
540    int yuvTexStrideY = stride;
541    int yuvTexOffsetV = yuvTexStrideY * h;
542    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
543    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
544    int yuvTexStrideU = yuvTexStrideV;
545    for (int x = 0; x < w; x++) {
546        for (int y = 0; y < h; y++) {
547            int parityX = (x / blockWidth) & 1;
548            int parityY = (y / blockHeight) & 1;
549            unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
550            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
551            if (x < w / 2 && y < h / 2) {
552                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
553                if (x * 2 < w / 2 && y * 2 < h / 2) {
554                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
555                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
556                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
557                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
558                        intensity;
559                }
560            }
561        }
562    }
563}
564
565// Fill a YV12 buffer with red outside a given rectangle and green inside it.
566void SurfaceMediaSourceTest::fillYV12BufferRect(uint8_t* buf, int w,
567                  int h, int stride, const android_native_rect_t& rect) {
568    const int yuvTexOffsetY = 0;
569    int yuvTexStrideY = stride;
570    int yuvTexOffsetV = yuvTexStrideY * h;
571    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
572    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
573    int yuvTexStrideU = yuvTexStrideV;
574    for (int x = 0; x < w; x++) {
575        for (int y = 0; y < h; y++) {
576            bool inside = rect.left <= x && x < rect.right &&
577                    rect.top <= y && y < rect.bottom;
578            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
579            if (x < w / 2 && y < h / 2) {
580                bool inside = rect.left <= 2*x && 2*x < rect.right &&
581                        rect.top <= 2*y && 2*y < rect.bottom;
582                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
583                buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
584                                                inside ? 16 : 255;
585            }
586        }
587    }
588}  ///////// End of class SurfaceMediaSourceTest
589
590///////////////////////////////////////////////////////////////////
591// Class to imitate the recording     /////////////////////////////
592// ////////////////////////////////////////////////////////////////
593struct SimpleDummyRecorder {
594        sp<MediaSource> mSource;
595
596        SimpleDummyRecorder
597                (const sp<MediaSource> &source): mSource(source) {}
598
599        status_t start() { return mSource->start();}
600        status_t stop()  { return mSource->stop();}
601
602        // fakes reading from a media source
603        status_t readFromSource() {
604            MediaBuffer *buffer;
605            status_t err = mSource->read(&buffer);
606            if (err != OK) {
607                return err;
608            }
609            buffer->release();
610            buffer = NULL;
611            return OK;
612        }
613};
614///////////////////////////////////////////////////////////////////
615//           TESTS
616// SurfaceMediaSourceTest class contains tests that fill the buffers
617// using the cpu calls
618// SurfaceMediaSourceGLTest class contains tests that fill the buffers
619// using the GL calls.
620// TODO: None of the tests actually verify the encoded images.. so at this point,
621// these are mostly functionality tests + visual inspection
622//////////////////////////////////////////////////////////////////////
623
624// Just pass one buffer from the native_window to the SurfaceMediaSource
625// Dummy Encoder
626static int testId = 1;
627TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotOneBufferPass) {
628    ALOGV("Test # %d", testId++);
629    ALOGV("Testing OneBufferPass ******************************");
630
631    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
632            HAL_PIXEL_FORMAT_YV12));
633    oneBufferPass(mYuvTexWidth, mYuvTexHeight);
634}
635
636// Pass the buffer with the wrong height and weight and should not be accepted
637// Dummy Encoder
638TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotWrongSizeBufferPass) {
639    ALOGV("Test # %d", testId++);
640    ALOGV("Testing Wrong size BufferPass ******************************");
641
642    // setting the client side buffer size different than the server size
643    ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
644             10, 10));
645    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
646            HAL_PIXEL_FORMAT_YV12));
647
648    ANativeWindowBuffer* anb;
649
650    // Note: make sure we get an ERROR back when dequeuing!
651    ASSERT_NE(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
652}
653
654// pass multiple buffers from the native_window the SurfaceMediaSource
655// Dummy Encoder
656TEST_F(SurfaceMediaSourceTest,  DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
657    ALOGV("Test # %d", testId++);
658    ALOGV("Testing MultiBufferPass, Dummy Recorder *********************");
659    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
660            HAL_PIXEL_FORMAT_YV12));
661
662    SimpleDummyRecorder writer(mSMS);
663    writer.start();
664
665    int32_t nFramesCount = 0;
666    while (nFramesCount < 300) {
667        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
668
669        ASSERT_EQ(NO_ERROR, writer.readFromSource());
670
671        nFramesCount++;
672    }
673    writer.stop();
674}
675
676// Delayed pass of multiple buffers from the native_window the SurfaceMediaSource
677// Dummy Encoder
678TEST_F(SurfaceMediaSourceTest,  DummyLagEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
679    ALOGV("Test # %d", testId++);
680    ALOGV("Testing MultiBufferPass, Dummy Recorder Lagging **************");
681
682    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
683            HAL_PIXEL_FORMAT_YV12));
684
685    SimpleDummyRecorder writer(mSMS);
686    writer.start();
687
688    int32_t nFramesCount = 1;
689    const int FRAMES_LAG = SurfaceMediaSource::MIN_UNDEQUEUED_BUFFERS;
690
691    while (nFramesCount <= 300) {
692        ALOGV("Frame: %d", nFramesCount);
693        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
694        // Forcing the writer to lag behind a few frames
695        if (nFramesCount > FRAMES_LAG) {
696            ASSERT_EQ(NO_ERROR, writer.readFromSource());
697        }
698        nFramesCount++;
699    }
700    writer.stop();
701}
702
703// pass multiple buffers from the native_window the SurfaceMediaSource
704// A dummy writer (MULTITHREADED) is used to simulate actual MPEG4Writer
705TEST_F(SurfaceMediaSourceTest, DummyThreadedEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
706    ALOGV("Test # %d", testId++);
707    ALOGV("Testing MultiBufferPass, Dummy Recorder Multi-Threaded **********");
708    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
709            HAL_PIXEL_FORMAT_YV12));
710
711    DummyRecorder writer(mSMS);
712    writer.start();
713
714    int32_t nFramesCount = 0;
715    while (nFramesCount <= 300) {
716        ALOGV("Frame: %d", nFramesCount);
717        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
718
719        nFramesCount++;
720    }
721    writer.stop();
722}
723
724// Test to examine actual encoding using mediarecorder
725// We use the mediaserver to create a mediarecorder and send
726// it back to us. So SurfaceMediaSource lives in the same process
727// as the mediaserver.
728// Very close to the actual camera, except that the
729// buffers are filled and queueud by the CPU instead of GL.
730TEST_F(SurfaceMediaSourceTest, DISABLED_EncodingFromCpuYV12BufferNpotWriteMediaServer) {
731    ALOGV("Test # %d", testId++);
732    ALOGV("************** Testing the whole pipeline with actual MediaRecorder ***********");
733    ALOGV("************** SurfaceMediaSource is same process as mediaserver    ***********");
734
735    const char *fileName = "/sdcard/outputSurfEncMSource.mp4";
736    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
737    if (fd < 0) {
738        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
739    }
740    CHECK(fd >= 0);
741
742    sp<MediaRecorder> mr = SurfaceMediaSourceGLTest::setUpMediaRecorder(fd,
743            VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264,
744            mYuvTexWidth, mYuvTexHeight, 30);
745    // get the reference to the surfacemediasource living in
746    // mediaserver that is created by stagefrightrecorder
747    sp<IGraphicBufferProducer> iST = mr->querySurfaceMediaSourceFromMediaServer();
748    mSTC = new Surface(iST);
749    mANW = mSTC;
750    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
751    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
752                                                HAL_PIXEL_FORMAT_YV12));
753
754    int32_t nFramesCount = 0;
755    while (nFramesCount <= 300) {
756        oneBufferPassNoFill(mYuvTexWidth, mYuvTexHeight);
757        nFramesCount++;
758        ALOGV("framesCount = %d", nFramesCount);
759    }
760
761    ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU));
762    ALOGV("Stopping MediaRecorder...");
763    CHECK_EQ((status_t)OK, mr->stop());
764    mr.clear();
765    close(fd);
766}
767
768//////////////////////////////////////////////////////////////////////
769// GL tests
770/////////////////////////////////////////////////////////////////////
771
772// Test to examine whether we can choose the Recordable Android GLConfig
773// DummyRecorder used- no real encoding here
774TEST_F(SurfaceMediaSourceGLTest, ChooseAndroidRecordableEGLConfigDummyWriter) {
775    ALOGV("Test # %d", testId++);
776    ALOGV("Verify creating a surface w/ right config + dummy writer*********");
777
778    mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
779    mSTC = new Surface(mSMS->getProducer());
780    mANW = mSTC;
781
782    DummyRecorder writer(mSMS);
783    writer.start();
784
785    if (mEglSurface != EGL_NO_SURFACE) {
786        EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface));
787        mEglSurface = EGL_NO_SURFACE;
788    }
789
790    mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
791                                mANW.get(), NULL);
792    ASSERT_EQ(EGL_SUCCESS, eglGetError());
793    ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ;
794
795    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
796            mEglContext));
797    ASSERT_EQ(EGL_SUCCESS, eglGetError());
798
799    int32_t nFramesCount = 0;
800    while (nFramesCount <= 300) {
801        oneBufferPassGL();
802        nFramesCount++;
803        ALOGV("framesCount = %d", nFramesCount);
804    }
805
806    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
807            EGL_NO_CONTEXT));
808    ASSERT_EQ(EGL_SUCCESS, eglGetError());
809    eglDestroySurface(mEglDisplay, mEglSurface);
810    mEglSurface = EGL_NO_SURFACE;
811
812    writer.stop();
813}
814// Test to examine whether we can render GL buffers in to the surface
815// created with the native window handle
816TEST_F(SurfaceMediaSourceGLTest, RenderingToRecordableEGLSurfaceWorks) {
817    ALOGV("Test # %d", testId++);
818    ALOGV("RenderingToRecordableEGLSurfaceWorks *********************");
819    // Do the producer side of things
820    glClearColor(0.6, 0.6, 0.6, 0.6);
821    glClear(GL_COLOR_BUFFER_BIT);
822
823    glEnable(GL_SCISSOR_TEST);
824    glScissor(4, 4, 4, 4);
825    glClearColor(1.0, 0.0, 0.0, 1.0);
826    glClear(GL_COLOR_BUFFER_BIT);
827
828    glScissor(24, 48, 4, 4);
829    glClearColor(0.0, 1.0, 0.0, 1.0);
830    glClear(GL_COLOR_BUFFER_BIT);
831
832    glScissor(37, 17, 4, 4);
833    glClearColor(0.0, 0.0, 1.0, 1.0);
834    glClear(GL_COLOR_BUFFER_BIT);
835
836    EXPECT_TRUE(checkPixel( 0,  0, 153, 153, 153, 153));
837    EXPECT_TRUE(checkPixel(63,  0, 153, 153, 153, 153));
838    EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
839    EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
840
841    EXPECT_TRUE(checkPixel( 4,  7, 255,   0,   0, 255));
842    EXPECT_TRUE(checkPixel(25, 51,   0, 255,   0, 255));
843    EXPECT_TRUE(checkPixel(40, 19,   0,   0, 255, 255));
844    EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
845    EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
846    EXPECT_TRUE(checkPixel(13,  8, 153, 153, 153, 153));
847    EXPECT_TRUE(checkPixel(46,  3, 153, 153, 153, 153));
848    EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
849    EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
850    EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
851    EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
852    EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
853    EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
854    EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
855    EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
856    EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
857}
858
859// Test to examine the actual encoding with GL buffers
860// Actual encoder, Actual GL Buffers Filled SurfaceMediaSource
861// The same pattern is rendered every frame
862TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaSameImageEachBufNpotWrite) {
863    ALOGV("Test # %d", testId++);
864    ALOGV("************** Testing the whole pipeline with actual Recorder ***********");
865    ALOGV("************** GL Filling the buffers ***********");
866    // Note: No need to set the colorformat for the buffers. The colorformat is
867    // in the GRAlloc buffers itself.
868
869    const char *fileName = "/sdcard/outputSurfEncMSourceGL.mp4";
870    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
871    if (fd < 0) {
872        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
873    }
874    CHECK(fd >= 0);
875
876    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE,
877            OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30);
878
879    // get the reference to the surfacemediasource living in
880    // mediaserver that is created by stagefrightrecorder
881    setUpEGLSurfaceFromMediaRecorder(mr);
882
883    int32_t nFramesCount = 0;
884    while (nFramesCount <= 300) {
885        oneBufferPassGL();
886        nFramesCount++;
887        ALOGV("framesCount = %d", nFramesCount);
888    }
889
890    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
891            EGL_NO_CONTEXT));
892    ASSERT_EQ(EGL_SUCCESS, eglGetError());
893    eglDestroySurface(mEglDisplay, mEglSurface);
894    mEglSurface = EGL_NO_SURFACE;
895
896    ALOGV("Stopping MediaRecorder...");
897    CHECK_EQ((status_t)OK, mr->stop());
898    mr.clear();
899    close(fd);
900}
901
902// Test to examine the actual encoding from the GL Buffers
903// Actual encoder, Actual GL Buffers Filled SurfaceMediaSource
904// A different pattern is rendered every frame
905TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaDiffImageEachBufNpotWrite) {
906    ALOGV("Test # %d", testId++);
907    ALOGV("************** Testing the whole pipeline with actual Recorder ***********");
908    ALOGV("************** Diff GL Filling the buffers ***********");
909    // Note: No need to set the colorformat for the buffers. The colorformat is
910    // in the GRAlloc buffers itself.
911
912    const char *fileName = "/sdcard/outputSurfEncMSourceGLDiff.mp4";
913    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
914    if (fd < 0) {
915        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
916    }
917    CHECK(fd >= 0);
918
919    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE,
920            OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30);
921
922    // get the reference to the surfacemediasource living in
923    // mediaserver that is created by stagefrightrecorder
924    setUpEGLSurfaceFromMediaRecorder(mr);
925
926    int32_t nFramesCount = 0;
927    while (nFramesCount <= 300) {
928        oneBufferPassGL(nFramesCount);
929        nFramesCount++;
930        ALOGV("framesCount = %d", nFramesCount);
931    }
932
933    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
934            EGL_NO_CONTEXT));
935    ASSERT_EQ(EGL_SUCCESS, eglGetError());
936    eglDestroySurface(mEglDisplay, mEglSurface);
937    mEglSurface = EGL_NO_SURFACE;
938
939    ALOGV("Stopping MediaRecorder...");
940    CHECK_EQ((status_t)OK, mr->stop());
941    mr.clear();
942    close(fd);
943}
944} // namespace android
945