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