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