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"),
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()))->getBufferQueue();
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
363        // Manual cast is required to avoid constructor ambiguity
364        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS->getBufferQueue()));
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->getBufferQueue()));
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    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(int width, int height ) {
529    ANativeWindowBuffer* anb;
530    ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
531    ASSERT_TRUE(anb != NULL);
532
533    // We do not fill the buffer in. Just queue it back.
534    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
535    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
536            -1));
537}
538
539// Fill a YV12 buffer with a multi-colored checkerboard pattern
540void SurfaceMediaSourceTest::fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
541    const int blockWidth = w > 16 ? w / 16 : 1;
542    const int blockHeight = h > 16 ? h / 16 : 1;
543    const int yuvTexOffsetY = 0;
544    int yuvTexStrideY = stride;
545    int yuvTexOffsetV = yuvTexStrideY * h;
546    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
547    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
548    int yuvTexStrideU = yuvTexStrideV;
549    for (int x = 0; x < w; x++) {
550        for (int y = 0; y < h; y++) {
551            int parityX = (x / blockWidth) & 1;
552            int parityY = (y / blockHeight) & 1;
553            unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
554            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
555            if (x < w / 2 && y < h / 2) {
556                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
557                if (x * 2 < w / 2 && y * 2 < h / 2) {
558                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
559                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
560                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
561                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
562                        intensity;
563                }
564            }
565        }
566    }
567}
568
569// Fill a YV12 buffer with red outside a given rectangle and green inside it.
570void SurfaceMediaSourceTest::fillYV12BufferRect(uint8_t* buf, int w,
571                  int h, int stride, const android_native_rect_t& rect) {
572    const int yuvTexOffsetY = 0;
573    int yuvTexStrideY = stride;
574    int yuvTexOffsetV = yuvTexStrideY * h;
575    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
576    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
577    int yuvTexStrideU = yuvTexStrideV;
578    for (int x = 0; x < w; x++) {
579        for (int y = 0; y < h; y++) {
580            bool inside = rect.left <= x && x < rect.right &&
581                    rect.top <= y && y < rect.bottom;
582            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
583            if (x < w / 2 && y < h / 2) {
584                bool inside = rect.left <= 2*x && 2*x < rect.right &&
585                        rect.top <= 2*y && 2*y < rect.bottom;
586                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
587                buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
588                                                inside ? 16 : 255;
589            }
590        }
591    }
592}  ///////// End of class SurfaceMediaSourceTest
593
594///////////////////////////////////////////////////////////////////
595// Class to imitate the recording     /////////////////////////////
596// ////////////////////////////////////////////////////////////////
597struct SimpleDummyRecorder {
598        sp<MediaSource> mSource;
599
600        SimpleDummyRecorder
601                (const sp<MediaSource> &source): mSource(source) {}
602
603        status_t start() { return mSource->start();}
604        status_t stop()  { return mSource->stop();}
605
606        // fakes reading from a media source
607        status_t readFromSource() {
608            MediaBuffer *buffer;
609            status_t err = mSource->read(&buffer);
610            if (err != OK) {
611                return err;
612            }
613            buffer->release();
614            buffer = NULL;
615            return OK;
616        }
617};
618///////////////////////////////////////////////////////////////////
619//           TESTS
620// SurfaceMediaSourceTest class contains tests that fill the buffers
621// using the cpu calls
622// SurfaceMediaSourceGLTest class contains tests that fill the buffers
623// using the GL calls.
624// TODO: None of the tests actually verify the encoded images.. so at this point,
625// these are mostly functionality tests + visual inspection
626//////////////////////////////////////////////////////////////////////
627
628// Just pass one buffer from the native_window to the SurfaceMediaSource
629// Dummy Encoder
630static int testId = 1;
631TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotOneBufferPass) {
632    ALOGV("Test # %d", testId++);
633    ALOGV("Testing OneBufferPass ******************************");
634
635    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
636            HAL_PIXEL_FORMAT_YV12));
637    oneBufferPass(mYuvTexWidth, mYuvTexHeight);
638}
639
640// Pass the buffer with the wrong height and weight and should not be accepted
641// Dummy Encoder
642TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotWrongSizeBufferPass) {
643    ALOGV("Test # %d", testId++);
644    ALOGV("Testing Wrong size BufferPass ******************************");
645
646    // setting the client side buffer size different than the server size
647    ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
648             10, 10));
649    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
650            HAL_PIXEL_FORMAT_YV12));
651
652    ANativeWindowBuffer* anb;
653
654    // Note: make sure we get an ERROR back when dequeuing!
655    ASSERT_NE(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
656}
657
658// pass multiple buffers from the native_window the SurfaceMediaSource
659// Dummy Encoder
660TEST_F(SurfaceMediaSourceTest,  DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
661    ALOGV("Test # %d", testId++);
662    ALOGV("Testing MultiBufferPass, Dummy Recorder *********************");
663    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
664            HAL_PIXEL_FORMAT_YV12));
665
666    SimpleDummyRecorder writer(mSMS);
667    writer.start();
668
669    int32_t nFramesCount = 0;
670    while (nFramesCount < 300) {
671        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
672
673        ASSERT_EQ(NO_ERROR, writer.readFromSource());
674
675        nFramesCount++;
676    }
677    writer.stop();
678}
679
680// Delayed pass of multiple buffers from the native_window the SurfaceMediaSource
681// Dummy Encoder
682TEST_F(SurfaceMediaSourceTest,  DummyLagEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
683    ALOGV("Test # %d", testId++);
684    ALOGV("Testing MultiBufferPass, Dummy Recorder Lagging **************");
685
686    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
687            HAL_PIXEL_FORMAT_YV12));
688
689    SimpleDummyRecorder writer(mSMS);
690    writer.start();
691
692    int32_t nFramesCount = 1;
693    const int FRAMES_LAG = SurfaceMediaSource::MIN_UNDEQUEUED_BUFFERS;
694
695    while (nFramesCount <= 300) {
696        ALOGV("Frame: %d", nFramesCount);
697        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
698        // Forcing the writer to lag behind a few frames
699        if (nFramesCount > FRAMES_LAG) {
700            ASSERT_EQ(NO_ERROR, writer.readFromSource());
701        }
702        nFramesCount++;
703    }
704    writer.stop();
705}
706
707// pass multiple buffers from the native_window the SurfaceMediaSource
708// A dummy writer (MULTITHREADED) is used to simulate actual MPEG4Writer
709TEST_F(SurfaceMediaSourceTest, DummyThreadedEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
710    ALOGV("Test # %d", testId++);
711    ALOGV("Testing MultiBufferPass, Dummy Recorder Multi-Threaded **********");
712    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
713            HAL_PIXEL_FORMAT_YV12));
714
715    DummyRecorder writer(mSMS);
716    writer.start();
717
718    int32_t nFramesCount = 0;
719    while (nFramesCount <= 300) {
720        ALOGV("Frame: %d", nFramesCount);
721        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
722
723        nFramesCount++;
724    }
725    writer.stop();
726}
727
728// Test to examine actual encoding using mediarecorder
729// We use the mediaserver to create a mediarecorder and send
730// it back to us. So SurfaceMediaSource lives in the same process
731// as the mediaserver.
732// Very close to the actual camera, except that the
733// buffers are filled and queueud by the CPU instead of GL.
734TEST_F(SurfaceMediaSourceTest, DISABLED_EncodingFromCpuYV12BufferNpotWriteMediaServer) {
735    ALOGV("Test # %d", testId++);
736    ALOGV("************** Testing the whole pipeline with actual MediaRecorder ***********");
737    ALOGV("************** SurfaceMediaSource is same process as mediaserver    ***********");
738
739    const char *fileName = "/sdcard/outputSurfEncMSource.mp4";
740    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
741    if (fd < 0) {
742        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
743    }
744    CHECK(fd >= 0);
745
746    sp<MediaRecorder> mr = SurfaceMediaSourceGLTest::setUpMediaRecorder(fd,
747            VIDEO_SOURCE_GRALLOC_BUFFER,
748            OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth,
749            mYuvTexHeight, 30);
750    // get the reference to the surfacemediasource living in
751    // mediaserver that is created by stagefrightrecorder
752    sp<ISurfaceTexture> iST = mr->querySurfaceMediaSourceFromMediaServer();
753    mSTC = new SurfaceTextureClient(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 SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS->getBufferQueue()));
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_GRALLOC_BUFFER,
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_GRALLOC_BUFFER,
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