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