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