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