SurfaceMediaSource_test.cpp revision abf0610a8cea021548f2909e1d47d656206f641c
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 <ui/GraphicBuffer.h>
30#include <gui/SurfaceTextureClient.h>
31#include <gui/ISurfaceComposer.h>
32#include <gui/Surface.h>
33#include <gui/SurfaceComposerClient.h>
34
35#include <binder/ProcessState.h>
36#include <ui/FramebufferNativeWindow.h>
37
38#include <media/stagefright/foundation/ADebug.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<ISurfaceTexture> 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        // Manual cast is required to avoid constructor ambiguity
364        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS));
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<SurfaceTextureClient> 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 SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS));
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<SurfaceTextureClient> 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();
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<ISurfaceTexture> iST = mr->querySurfaceMediaSourceFromMediaServer();
486    mSTC = new SurfaceTextureClient(iST);
487    mANW = mSTC;
488
489    mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
490                                mANW.get(), NULL);
491    ASSERT_EQ(EGL_SUCCESS, eglGetError());
492    ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ;
493
494    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
495            mEglContext));
496    ASSERT_EQ(EGL_SUCCESS, eglGetError());
497}
498
499
500/////////////////////////////////////////////////////////////////////
501// Methods in SurfaceMediaSourceTest
502/////////////////////////////////////////////////////////////////////
503
504// One pass of dequeuing and queuing the buffer. Fill it in with
505// cpu YV12 buffer
506void SurfaceMediaSourceTest::oneBufferPass(int width, int height ) {
507    ANativeWindowBuffer* anb;
508    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
509    ASSERT_TRUE(anb != NULL);
510
511    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
512    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
513
514    // Fill the buffer with the a checkerboard pattern
515    uint8_t* img = NULL;
516    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
517    SurfaceMediaSourceTest::fillYV12Buffer(img, width, height, buf->getStride());
518    buf->unlock();
519
520    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
521}
522
523// Dequeuing and queuing the buffer without really filling it in.
524void SurfaceMediaSourceTest::oneBufferPassNoFill(int width, int height ) {
525    ANativeWindowBuffer* anb;
526    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
527    ASSERT_TRUE(anb != NULL);
528
529    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
530    // ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
531    // We do not fill the buffer in. Just queue it back.
532    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
533}
534
535// Fill a YV12 buffer with a multi-colored checkerboard pattern
536void SurfaceMediaSourceTest::fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
537    const int blockWidth = w > 16 ? w / 16 : 1;
538    const int blockHeight = h > 16 ? h / 16 : 1;
539    const int yuvTexOffsetY = 0;
540    int yuvTexStrideY = stride;
541    int yuvTexOffsetV = yuvTexStrideY * h;
542    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
543    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
544    int yuvTexStrideU = yuvTexStrideV;
545    for (int x = 0; x < w; x++) {
546        for (int y = 0; y < h; y++) {
547            int parityX = (x / blockWidth) & 1;
548            int parityY = (y / blockHeight) & 1;
549            unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
550            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
551            if (x < w / 2 && y < h / 2) {
552                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
553                if (x * 2 < w / 2 && y * 2 < h / 2) {
554                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
555                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
556                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
557                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
558                        intensity;
559                }
560            }
561        }
562    }
563}
564
565// Fill a YV12 buffer with red outside a given rectangle and green inside it.
566void SurfaceMediaSourceTest::fillYV12BufferRect(uint8_t* buf, int w,
567                  int h, int stride, const android_native_rect_t& rect) {
568    const int yuvTexOffsetY = 0;
569    int yuvTexStrideY = stride;
570    int yuvTexOffsetV = yuvTexStrideY * h;
571    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
572    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
573    int yuvTexStrideU = yuvTexStrideV;
574    for (int x = 0; x < w; x++) {
575        for (int y = 0; y < h; y++) {
576            bool inside = rect.left <= x && x < rect.right &&
577                    rect.top <= y && y < rect.bottom;
578            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
579            if (x < w / 2 && y < h / 2) {
580                bool inside = rect.left <= 2*x && 2*x < rect.right &&
581                        rect.top <= 2*y && 2*y < rect.bottom;
582                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
583                buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
584                                                inside ? 16 : 255;
585            }
586        }
587    }
588}  ///////// End of class SurfaceMediaSourceTest
589
590///////////////////////////////////////////////////////////////////
591// Class to imitate the recording     /////////////////////////////
592// ////////////////////////////////////////////////////////////////
593struct SimpleDummyRecorder {
594        sp<MediaSource> mSource;
595
596        SimpleDummyRecorder
597                (const sp<MediaSource> &source): mSource(source) {}
598
599        status_t start() { return mSource->start();}
600        status_t stop()  { return mSource->stop();}
601
602        // fakes reading from a media source
603        status_t readFromSource() {
604            MediaBuffer *buffer;
605            status_t err = mSource->read(&buffer);
606            if (err != OK) {
607                return err;
608            }
609            buffer->release();
610            buffer = NULL;
611            return OK;
612        }
613};
614///////////////////////////////////////////////////////////////////
615//           TESTS
616// SurfaceMediaSourceTest class contains tests that fill the buffers
617// using the cpu calls
618// SurfaceMediaSourceGLTest class contains tests that fill the buffers
619// using the GL calls.
620// TODO: None of the tests actually verify the encoded images.. so at this point,
621// these are mostly functionality tests + visual inspection
622//////////////////////////////////////////////////////////////////////
623
624// Just pass one buffer from the native_window to the SurfaceMediaSource
625// Dummy Encoder
626static int testId = 1;
627TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotOneBufferPass) {
628    ALOGV("Test # %d", testId++);
629    ALOGV("Testing OneBufferPass ******************************");
630
631    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
632            HAL_PIXEL_FORMAT_YV12));
633    oneBufferPass(mYuvTexWidth, mYuvTexHeight);
634}
635
636// Pass the buffer with the wrong height and weight and should not be accepted
637// Dummy Encoder
638TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotWrongSizeBufferPass) {
639    ALOGV("Test # %d", testId++);
640    ALOGV("Testing Wrong size BufferPass ******************************");
641
642    // setting the client side buffer size different than the server size
643    ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
644             10, 10));
645    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
646            HAL_PIXEL_FORMAT_YV12));
647
648    ANativeWindowBuffer* anb;
649
650    // Note: make sure we get an ERROR back when dequeuing!
651    ASSERT_NE(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
652}
653
654// pass multiple buffers from the native_window the SurfaceMediaSource
655// Dummy Encoder
656TEST_F(SurfaceMediaSourceTest,  DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
657    ALOGV("Test # %d", testId++);
658    ALOGV("Testing MultiBufferPass, Dummy Recorder *********************");
659    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
660            HAL_PIXEL_FORMAT_YV12));
661
662    SimpleDummyRecorder writer(mSMS);
663    writer.start();
664
665    int32_t nFramesCount = 0;
666    while (nFramesCount < 300) {
667        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
668
669        ASSERT_EQ(NO_ERROR, writer.readFromSource());
670
671        nFramesCount++;
672    }
673    writer.stop();
674}
675
676// Delayed pass of multiple buffers from the native_window the SurfaceMediaSource
677// Dummy Encoder
678TEST_F(SurfaceMediaSourceTest,  DISABLED_DummyLagEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
679    ALOGV("Test # %d", testId++);
680    ALOGV("Testing MultiBufferPass, Dummy Recorder Lagging **************");
681
682    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
683            HAL_PIXEL_FORMAT_YV12));
684
685    SimpleDummyRecorder writer(mSMS);
686    writer.start();
687
688    int32_t nFramesCount = 1;
689    const int FRAMES_LAG = mSMS->getBufferCount() - 1;
690    while (nFramesCount <= 300) {
691        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
692        // Forcing the writer to lag behind a few frames
693        if (nFramesCount > FRAMES_LAG) {
694            ASSERT_EQ(NO_ERROR, writer.readFromSource());
695        }
696        nFramesCount++;
697    }
698    writer.stop();
699}
700
701// pass multiple buffers from the native_window the SurfaceMediaSource
702// A dummy writer (MULTITHREADED) is used to simulate actual MPEG4Writer
703TEST_F(SurfaceMediaSourceTest, DISABLED_DummyThreadedEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
704    ALOGV("Test # %d", testId++);
705    ALOGV("Testing MultiBufferPass, Dummy Recorder Multi-Threaded **********");
706    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
707            HAL_PIXEL_FORMAT_YV12));
708
709    DummyRecorder writer(mSMS);
710    writer.start();
711
712    int32_t nFramesCount = 0;
713    while (nFramesCount <= 300) {
714        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
715
716        nFramesCount++;
717    }
718    writer.stop();
719}
720
721// Test to examine actual encoding using mediarecorder
722// We use the mediaserver to create a mediarecorder and send
723// it back to us. So SurfaceMediaSource lives in the same process
724// as the mediaserver.
725// Very close to the actual camera, except that the
726// buffers are filled and queueud by the CPU instead of GL.
727TEST_F(SurfaceMediaSourceTest, DISABLED_EncodingFromCpuYV12BufferNpotWriteMediaServer) {
728    ALOGV("Test # %d", testId++);
729    ALOGV("************** Testing the whole pipeline with actual MediaRecorder ***********");
730    ALOGV("************** SurfaceMediaSource is same process as mediaserver    ***********");
731
732    const char *fileName = "/sdcard/outputSurfEncMSource.mp4";
733    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
734    if (fd < 0) {
735        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
736    }
737    CHECK(fd >= 0);
738
739    sp<MediaRecorder> mr = SurfaceMediaSourceGLTest::setUpMediaRecorder(fd,
740            VIDEO_SOURCE_GRALLOC_BUFFER,
741            OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth,
742            mYuvTexHeight, 30);
743    // get the reference to the surfacemediasource living in
744    // mediaserver that is created by stagefrightrecorder
745    sp<ISurfaceTexture> iST = mr->querySurfaceMediaSourceFromMediaServer();
746    mSTC = new SurfaceTextureClient(iST);
747    mANW = mSTC;
748    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
749    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
750                                                HAL_PIXEL_FORMAT_YV12));
751
752    int32_t nFramesCount = 0;
753    while (nFramesCount <= 300) {
754        oneBufferPassNoFill(mYuvTexWidth, mYuvTexHeight);
755        nFramesCount++;
756        ALOGV("framesCount = %d", nFramesCount);
757    }
758
759    ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU));
760    ALOGV("Stopping MediaRecorder...");
761    CHECK_EQ((status_t)OK, mr->stop());
762    mr.clear();
763    close(fd);
764}
765
766//////////////////////////////////////////////////////////////////////
767// GL tests
768/////////////////////////////////////////////////////////////////////
769
770// Test to examine whether we can choose the Recordable Android GLConfig
771// DummyRecorder used- no real encoding here
772TEST_F(SurfaceMediaSourceGLTest, ChooseAndroidRecordableEGLConfigDummyWriter) {
773    ALOGV("Test # %d", testId++);
774    ALOGV("Verify creating a surface w/ right config + dummy writer*********");
775
776    mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
777    mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS));
778    mANW = mSTC;
779
780    DummyRecorder writer(mSMS);
781    writer.start();
782
783    mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
784                                mANW.get(), NULL);
785    ASSERT_EQ(EGL_SUCCESS, eglGetError());
786    ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ;
787
788    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
789            mEglContext));
790    ASSERT_EQ(EGL_SUCCESS, eglGetError());
791
792    int32_t nFramesCount = 0;
793    while (nFramesCount <= 300) {
794        oneBufferPassGL();
795        nFramesCount++;
796        ALOGV("framesCount = %d", nFramesCount);
797    }
798
799    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
800            EGL_NO_CONTEXT));
801    ASSERT_EQ(EGL_SUCCESS, eglGetError());
802    eglDestroySurface(mEglDisplay, mEglSurface);
803    mEglSurface = EGL_NO_SURFACE;
804
805    writer.stop();
806}
807// Test to examine whether we can render GL buffers in to the surface
808// created with the native window handle
809TEST_F(SurfaceMediaSourceGLTest, RenderingToRecordableEGLSurfaceWorks) {
810    ALOGV("Test # %d", testId++);
811    ALOGV("RenderingToRecordableEGLSurfaceWorks *********************");
812    // Do the producer side of things
813    glClearColor(0.6, 0.6, 0.6, 0.6);
814    glClear(GL_COLOR_BUFFER_BIT);
815
816    glEnable(GL_SCISSOR_TEST);
817    glScissor(4, 4, 4, 4);
818    glClearColor(1.0, 0.0, 0.0, 1.0);
819    glClear(GL_COLOR_BUFFER_BIT);
820
821    glScissor(24, 48, 4, 4);
822    glClearColor(0.0, 1.0, 0.0, 1.0);
823    glClear(GL_COLOR_BUFFER_BIT);
824
825    glScissor(37, 17, 4, 4);
826    glClearColor(0.0, 0.0, 1.0, 1.0);
827    glClear(GL_COLOR_BUFFER_BIT);
828
829    EXPECT_TRUE(checkPixel( 0,  0, 153, 153, 153, 153));
830    EXPECT_TRUE(checkPixel(63,  0, 153, 153, 153, 153));
831    EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
832    EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
833
834    EXPECT_TRUE(checkPixel( 4,  7, 255,   0,   0, 255));
835    EXPECT_TRUE(checkPixel(25, 51,   0, 255,   0, 255));
836    EXPECT_TRUE(checkPixel(40, 19,   0,   0, 255, 255));
837    EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
838    EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
839    EXPECT_TRUE(checkPixel(13,  8, 153, 153, 153, 153));
840    EXPECT_TRUE(checkPixel(46,  3, 153, 153, 153, 153));
841    EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
842    EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
843    EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
844    EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
845    EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
846    EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
847    EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
848    EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
849    EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
850}
851
852// Test to examine the actual encoding with GL buffers
853// Actual encoder, Actual GL Buffers Filled SurfaceMediaSource
854// The same pattern is rendered every frame
855TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaSameImageEachBufNpotWrite) {
856    ALOGV("Test # %d", testId++);
857    ALOGV("************** Testing the whole pipeline with actual Recorder ***********");
858    ALOGV("************** GL Filling the buffers ***********");
859    // Note: No need to set the colorformat for the buffers. The colorformat is
860    // in the GRAlloc buffers itself.
861
862    const char *fileName = "/sdcard/outputSurfEncMSourceGL.mp4";
863    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
864    if (fd < 0) {
865        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
866    }
867    CHECK(fd >= 0);
868
869    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_GRALLOC_BUFFER,
870            OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30);
871
872    // get the reference to the surfacemediasource living in
873    // mediaserver that is created by stagefrightrecorder
874    setUpEGLSurfaceFromMediaRecorder(mr);
875
876    int32_t nFramesCount = 0;
877    while (nFramesCount <= 300) {
878        oneBufferPassGL();
879        nFramesCount++;
880        ALOGV("framesCount = %d", nFramesCount);
881    }
882
883    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
884            EGL_NO_CONTEXT));
885    ASSERT_EQ(EGL_SUCCESS, eglGetError());
886    eglDestroySurface(mEglDisplay, mEglSurface);
887    mEglSurface = EGL_NO_SURFACE;
888
889    ALOGV("Stopping MediaRecorder...");
890    CHECK_EQ((status_t)OK, mr->stop());
891    mr.clear();
892    close(fd);
893}
894
895// Test to examine the actual encoding from the GL Buffers
896// Actual encoder, Actual GL Buffers Filled SurfaceMediaSource
897// A different pattern is rendered every frame
898TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaDiffImageEachBufNpotWrite) {
899    ALOGV("Test # %d", testId++);
900    ALOGV("************** Testing the whole pipeline with actual Recorder ***********");
901    ALOGV("************** Diff GL Filling the buffers ***********");
902    // Note: No need to set the colorformat for the buffers. The colorformat is
903    // in the GRAlloc buffers itself.
904
905    const char *fileName = "/sdcard/outputSurfEncMSourceGLDiff.mp4";
906    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
907    if (fd < 0) {
908        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
909    }
910    CHECK(fd >= 0);
911
912    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_GRALLOC_BUFFER,
913            OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30);
914
915    // get the reference to the surfacemediasource living in
916    // mediaserver that is created by stagefrightrecorder
917    setUpEGLSurfaceFromMediaRecorder(mr);
918
919    int32_t nFramesCount = 0;
920    while (nFramesCount <= 300) {
921        oneBufferPassGL(nFramesCount);
922        nFramesCount++;
923        ALOGV("framesCount = %d", nFramesCount);
924    }
925
926    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
927            EGL_NO_CONTEXT));
928    ASSERT_EQ(EGL_SUCCESS, eglGetError());
929    eglDestroySurface(mEglDisplay, mEglSurface);
930    mEglSurface = EGL_NO_SURFACE;
931
932    ALOGV("Stopping MediaRecorder...");
933    CHECK_EQ((status_t)OK, mr->stop());
934    mr.clear();
935    close(fd);
936}
937} // namespace android
938