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