SurfaceMediaSource_test.cpp revision be71aa29a3c86d2e01cd17839d2a72ab09a1bce5
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 <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()))->getProducer(); 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 mSTC = new Surface(mSMS->getProducer()); 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<Surface> mSTC; 379 sp<ANativeWindow> mANW; 380}; 381 382/////////////////////////////////////////////////////////////////////// 383// Class for the GL tests 384/////////////////////////////////////////////////////////////////////// 385class SurfaceMediaSourceGLTest : public GLTest { 386public: 387 388 SurfaceMediaSourceGLTest( ): mYuvTexWidth(176), mYuvTexHeight(144) { } 389 virtual EGLint const* getConfigAttribs(); 390 void oneBufferPassGL(int num = 0); 391 static sp<MediaRecorder> setUpMediaRecorder(int fileDescriptor, int videoSource, 392 int outputFormat, int videoEncoder, int width, int height, int fps); 393protected: 394 395 virtual void SetUp() { 396 ALOGV("SMS-GLTest::SetUp()"); 397 android::ProcessState::self()->startThreadPool(); 398 mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight); 399 mSTC = new Surface(mSMS->getProducer()); 400 mANW = mSTC; 401 402 // Doing the setup related to the GL Side 403 GLTest::SetUp(); 404 } 405 406 virtual void TearDown() { 407 mSMS.clear(); 408 mSTC.clear(); 409 mANW.clear(); 410 GLTest::TearDown(); 411 } 412 413 void setUpEGLSurfaceFromMediaRecorder(sp<MediaRecorder>& mr); 414 415 const int mYuvTexWidth; 416 const int mYuvTexHeight; 417 418 sp<SurfaceMediaSource> mSMS; 419 sp<Surface> mSTC; 420 sp<ANativeWindow> mANW; 421}; 422 423///////////////////////////////////////////////////////////////////// 424// Methods in SurfaceMediaSourceGLTest 425///////////////////////////////////////////////////////////////////// 426EGLint const* SurfaceMediaSourceGLTest::getConfigAttribs() { 427 ALOGV("SurfaceMediaSourceGLTest getConfigAttribs"); 428 static EGLint sDefaultConfigAttribs[] = { 429 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 430 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 431 EGL_RED_SIZE, 8, 432 EGL_GREEN_SIZE, 8, 433 EGL_BLUE_SIZE, 8, 434 EGL_RECORDABLE_ANDROID, EGL_TRUE, 435 EGL_NONE }; 436 437 return sDefaultConfigAttribs; 438} 439 440// One pass of dequeuing and queuing a GLBuffer 441void SurfaceMediaSourceGLTest::oneBufferPassGL(int num) { 442 int d = num % 50; 443 float f = 0.2f; // 0.1f * d; 444 445 glClearColor(0, 0.3, 0, 0.6); 446 glClear(GL_COLOR_BUFFER_BIT); 447 448 glEnable(GL_SCISSOR_TEST); 449 glScissor(4 + d, 4 + d, 4, 4); 450 glClearColor(1.0 - f, f, f, 1.0); 451 glClear(GL_COLOR_BUFFER_BIT); 452 453 glScissor(24 + d, 48 + d, 4, 4); 454 glClearColor(f, 1.0 - f, f, 1.0); 455 glClear(GL_COLOR_BUFFER_BIT); 456 457 glScissor(37 + d, 17 + d, 4, 4); 458 glClearColor(f, f, 1.0 - f, 1.0); 459 glClear(GL_COLOR_BUFFER_BIT); 460 461 // The following call dequeues and queues the buffer 462 eglSwapBuffers(mEglDisplay, mEglSurface); 463 ASSERT_EQ(EGL_SUCCESS, eglGetError()); 464 glDisable(GL_SCISSOR_TEST); 465} 466 467// Set up the MediaRecorder which runs in the same process as mediaserver 468sp<MediaRecorder> SurfaceMediaSourceGLTest::setUpMediaRecorder(int fd, int videoSource, 469 int outputFormat, int videoEncoder, int width, int height, int fps) { 470 sp<MediaRecorder> mr = new MediaRecorder(String16()); 471 mr->setVideoSource(videoSource); 472 mr->setOutputFormat(outputFormat); 473 mr->setVideoEncoder(videoEncoder); 474 mr->setOutputFile(fd, 0, 0); 475 mr->setVideoSize(width, height); 476 mr->setVideoFrameRate(fps); 477 mr->prepare(); 478 ALOGV("Starting MediaRecorder..."); 479 CHECK_EQ((status_t)OK, mr->start()); 480 return mr; 481} 482 483// query the mediarecorder for a surfacemeidasource and create an egl surface with that 484void SurfaceMediaSourceGLTest::setUpEGLSurfaceFromMediaRecorder(sp<MediaRecorder>& mr) { 485 sp<IGraphicBufferProducer> iST = mr->querySurfaceMediaSourceFromMediaServer(); 486 mSTC = new Surface(iST); 487 mANW = mSTC; 488 489 if (mEglSurface != EGL_NO_SURFACE) { 490 EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface)); 491 mEglSurface = EGL_NO_SURFACE; 492 } 493 mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, 494 mANW.get(), NULL); 495 ASSERT_EQ(EGL_SUCCESS, eglGetError()); 496 ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ; 497 498 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, 499 mEglContext)); 500 ASSERT_EQ(EGL_SUCCESS, eglGetError()); 501} 502 503 504///////////////////////////////////////////////////////////////////// 505// Methods in SurfaceMediaSourceTest 506///////////////////////////////////////////////////////////////////// 507 508// One pass of dequeuing and queuing the buffer. Fill it in with 509// cpu YV12 buffer 510void SurfaceMediaSourceTest::oneBufferPass(int width, int height ) { 511 ANativeWindowBuffer* anb; 512 ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); 513 ASSERT_TRUE(anb != NULL); 514 515 516 // Fill the buffer with the a checkerboard pattern 517 uint8_t* img = NULL; 518 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); 519 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 520 SurfaceMediaSourceTest::fillYV12Buffer(img, width, height, buf->getStride()); 521 buf->unlock(); 522 523 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), 524 -1)); 525} 526 527// Dequeuing and queuing the buffer without really filling it in. 528void SurfaceMediaSourceTest::oneBufferPassNoFill( 529 int /* width */, int /* height */) { 530 ANativeWindowBuffer* anb; 531 ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); 532 ASSERT_TRUE(anb != NULL); 533 534 // We do not fill the buffer in. Just queue it back. 535 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); 536 ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), 537 -1)); 538} 539 540// Fill a YV12 buffer with a multi-colored checkerboard pattern 541void SurfaceMediaSourceTest::fillYV12Buffer(uint8_t* buf, int w, int h, int stride) { 542 const int blockWidth = w > 16 ? w / 16 : 1; 543 const int blockHeight = h > 16 ? h / 16 : 1; 544 const int yuvTexOffsetY = 0; 545 int yuvTexStrideY = stride; 546 int yuvTexOffsetV = yuvTexStrideY * h; 547 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; 548 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2; 549 int yuvTexStrideU = yuvTexStrideV; 550 for (int x = 0; x < w; x++) { 551 for (int y = 0; y < h; y++) { 552 int parityX = (x / blockWidth) & 1; 553 int parityY = (y / blockHeight) & 1; 554 unsigned char intensity = (parityX ^ parityY) ? 63 : 191; 555 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; 556 if (x < w / 2 && y < h / 2) { 557 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity; 558 if (x * 2 < w / 2 && y * 2 < h / 2) { 559 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] = 560 buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] = 561 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] = 562 buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] = 563 intensity; 564 } 565 } 566 } 567 } 568} 569 570// Fill a YV12 buffer with red outside a given rectangle and green inside it. 571void SurfaceMediaSourceTest::fillYV12BufferRect(uint8_t* buf, int w, 572 int h, int stride, const android_native_rect_t& rect) { 573 const int yuvTexOffsetY = 0; 574 int yuvTexStrideY = stride; 575 int yuvTexOffsetV = yuvTexStrideY * h; 576 int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf; 577 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2; 578 int yuvTexStrideU = yuvTexStrideV; 579 for (int x = 0; x < w; x++) { 580 for (int y = 0; y < h; y++) { 581 bool inside = rect.left <= x && x < rect.right && 582 rect.top <= y && y < rect.bottom; 583 buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64; 584 if (x < w / 2 && y < h / 2) { 585 bool inside = rect.left <= 2*x && 2*x < rect.right && 586 rect.top <= 2*y && 2*y < rect.bottom; 587 buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16; 588 buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] = 589 inside ? 16 : 255; 590 } 591 } 592 } 593} ///////// End of class SurfaceMediaSourceTest 594 595/////////////////////////////////////////////////////////////////// 596// Class to imitate the recording ///////////////////////////// 597// //////////////////////////////////////////////////////////////// 598struct SimpleDummyRecorder { 599 sp<MediaSource> mSource; 600 601 SimpleDummyRecorder 602 (const sp<MediaSource> &source): mSource(source) {} 603 604 status_t start() { return mSource->start();} 605 status_t stop() { return mSource->stop();} 606 607 // fakes reading from a media source 608 status_t readFromSource() { 609 MediaBuffer *buffer; 610 status_t err = mSource->read(&buffer); 611 if (err != OK) { 612 return err; 613 } 614 buffer->release(); 615 buffer = NULL; 616 return OK; 617 } 618}; 619/////////////////////////////////////////////////////////////////// 620// TESTS 621// SurfaceMediaSourceTest class contains tests that fill the buffers 622// using the cpu calls 623// SurfaceMediaSourceGLTest class contains tests that fill the buffers 624// using the GL calls. 625// TODO: None of the tests actually verify the encoded images.. so at this point, 626// these are mostly functionality tests + visual inspection 627////////////////////////////////////////////////////////////////////// 628 629// Just pass one buffer from the native_window to the SurfaceMediaSource 630// Dummy Encoder 631static int testId = 1; 632TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotOneBufferPass) { 633 ALOGV("Test # %d", testId++); 634 ALOGV("Testing OneBufferPass ******************************"); 635 636 ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), 637 HAL_PIXEL_FORMAT_YV12)); 638 oneBufferPass(mYuvTexWidth, mYuvTexHeight); 639} 640 641// Pass the buffer with the wrong height and weight and should not be accepted 642// Dummy Encoder 643TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotWrongSizeBufferPass) { 644 ALOGV("Test # %d", testId++); 645 ALOGV("Testing Wrong size BufferPass ******************************"); 646 647 // setting the client side buffer size different than the server size 648 ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(), 649 10, 10)); 650 ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), 651 HAL_PIXEL_FORMAT_YV12)); 652 653 ANativeWindowBuffer* anb; 654 655 // Note: make sure we get an ERROR back when dequeuing! 656 ASSERT_NE(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); 657} 658 659// pass multiple buffers from the native_window the SurfaceMediaSource 660// Dummy Encoder 661TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) { 662 ALOGV("Test # %d", testId++); 663 ALOGV("Testing MultiBufferPass, Dummy Recorder *********************"); 664 ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), 665 HAL_PIXEL_FORMAT_YV12)); 666 667 SimpleDummyRecorder writer(mSMS); 668 writer.start(); 669 670 int32_t nFramesCount = 0; 671 while (nFramesCount < 300) { 672 oneBufferPass(mYuvTexWidth, mYuvTexHeight); 673 674 ASSERT_EQ(NO_ERROR, writer.readFromSource()); 675 676 nFramesCount++; 677 } 678 writer.stop(); 679} 680 681// Delayed pass of multiple buffers from the native_window the SurfaceMediaSource 682// Dummy Encoder 683TEST_F(SurfaceMediaSourceTest, DummyLagEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) { 684 ALOGV("Test # %d", testId++); 685 ALOGV("Testing MultiBufferPass, Dummy Recorder Lagging **************"); 686 687 ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), 688 HAL_PIXEL_FORMAT_YV12)); 689 690 SimpleDummyRecorder writer(mSMS); 691 writer.start(); 692 693 int32_t nFramesCount = 1; 694 const int FRAMES_LAG = SurfaceMediaSource::MIN_UNDEQUEUED_BUFFERS; 695 696 while (nFramesCount <= 300) { 697 ALOGV("Frame: %d", nFramesCount); 698 oneBufferPass(mYuvTexWidth, mYuvTexHeight); 699 // Forcing the writer to lag behind a few frames 700 if (nFramesCount > FRAMES_LAG) { 701 ASSERT_EQ(NO_ERROR, writer.readFromSource()); 702 } 703 nFramesCount++; 704 } 705 writer.stop(); 706} 707 708// pass multiple buffers from the native_window the SurfaceMediaSource 709// A dummy writer (MULTITHREADED) is used to simulate actual MPEG4Writer 710TEST_F(SurfaceMediaSourceTest, DummyThreadedEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) { 711 ALOGV("Test # %d", testId++); 712 ALOGV("Testing MultiBufferPass, Dummy Recorder Multi-Threaded **********"); 713 ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), 714 HAL_PIXEL_FORMAT_YV12)); 715 716 DummyRecorder writer(mSMS); 717 writer.start(); 718 719 int32_t nFramesCount = 0; 720 while (nFramesCount <= 300) { 721 ALOGV("Frame: %d", nFramesCount); 722 oneBufferPass(mYuvTexWidth, mYuvTexHeight); 723 724 nFramesCount++; 725 } 726 writer.stop(); 727} 728 729// Test to examine actual encoding using mediarecorder 730// We use the mediaserver to create a mediarecorder and send 731// it back to us. So SurfaceMediaSource lives in the same process 732// as the mediaserver. 733// Very close to the actual camera, except that the 734// buffers are filled and queueud by the CPU instead of GL. 735TEST_F(SurfaceMediaSourceTest, DISABLED_EncodingFromCpuYV12BufferNpotWriteMediaServer) { 736 ALOGV("Test # %d", testId++); 737 ALOGV("************** Testing the whole pipeline with actual MediaRecorder ***********"); 738 ALOGV("************** SurfaceMediaSource is same process as mediaserver ***********"); 739 740 const char *fileName = "/sdcard/outputSurfEncMSource.mp4"; 741 int fd = open(fileName, O_RDWR | O_CREAT, 0744); 742 if (fd < 0) { 743 ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd); 744 } 745 CHECK(fd >= 0); 746 747 sp<MediaRecorder> mr = SurfaceMediaSourceGLTest::setUpMediaRecorder(fd, 748 VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, 749 mYuvTexWidth, mYuvTexHeight, 30); 750 // get the reference to the surfacemediasource living in 751 // mediaserver that is created by stagefrightrecorder 752 sp<IGraphicBufferProducer> iST = mr->querySurfaceMediaSourceFromMediaServer(); 753 mSTC = new Surface(iST); 754 mANW = mSTC; 755 ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU)); 756 ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(), 757 HAL_PIXEL_FORMAT_YV12)); 758 759 int32_t nFramesCount = 0; 760 while (nFramesCount <= 300) { 761 oneBufferPassNoFill(mYuvTexWidth, mYuvTexHeight); 762 nFramesCount++; 763 ALOGV("framesCount = %d", nFramesCount); 764 } 765 766 ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU)); 767 ALOGV("Stopping MediaRecorder..."); 768 CHECK_EQ((status_t)OK, mr->stop()); 769 mr.clear(); 770 close(fd); 771} 772 773////////////////////////////////////////////////////////////////////// 774// GL tests 775///////////////////////////////////////////////////////////////////// 776 777// Test to examine whether we can choose the Recordable Android GLConfig 778// DummyRecorder used- no real encoding here 779TEST_F(SurfaceMediaSourceGLTest, ChooseAndroidRecordableEGLConfigDummyWriter) { 780 ALOGV("Test # %d", testId++); 781 ALOGV("Verify creating a surface w/ right config + dummy writer*********"); 782 783 mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight); 784 mSTC = new Surface(mSMS->getProducer()); 785 mANW = mSTC; 786 787 DummyRecorder writer(mSMS); 788 writer.start(); 789 790 if (mEglSurface != EGL_NO_SURFACE) { 791 EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface)); 792 mEglSurface = EGL_NO_SURFACE; 793 } 794 795 mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig, 796 mANW.get(), NULL); 797 ASSERT_EQ(EGL_SUCCESS, eglGetError()); 798 ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ; 799 800 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, 801 mEglContext)); 802 ASSERT_EQ(EGL_SUCCESS, eglGetError()); 803 804 int32_t nFramesCount = 0; 805 while (nFramesCount <= 300) { 806 oneBufferPassGL(); 807 nFramesCount++; 808 ALOGV("framesCount = %d", nFramesCount); 809 } 810 811 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, 812 EGL_NO_CONTEXT)); 813 ASSERT_EQ(EGL_SUCCESS, eglGetError()); 814 eglDestroySurface(mEglDisplay, mEglSurface); 815 mEglSurface = EGL_NO_SURFACE; 816 817 writer.stop(); 818} 819// Test to examine whether we can render GL buffers in to the surface 820// created with the native window handle 821TEST_F(SurfaceMediaSourceGLTest, RenderingToRecordableEGLSurfaceWorks) { 822 ALOGV("Test # %d", testId++); 823 ALOGV("RenderingToRecordableEGLSurfaceWorks *********************"); 824 // Do the producer side of things 825 glClearColor(0.6, 0.6, 0.6, 0.6); 826 glClear(GL_COLOR_BUFFER_BIT); 827 828 glEnable(GL_SCISSOR_TEST); 829 glScissor(4, 4, 4, 4); 830 glClearColor(1.0, 0.0, 0.0, 1.0); 831 glClear(GL_COLOR_BUFFER_BIT); 832 833 glScissor(24, 48, 4, 4); 834 glClearColor(0.0, 1.0, 0.0, 1.0); 835 glClear(GL_COLOR_BUFFER_BIT); 836 837 glScissor(37, 17, 4, 4); 838 glClearColor(0.0, 0.0, 1.0, 1.0); 839 glClear(GL_COLOR_BUFFER_BIT); 840 841 EXPECT_TRUE(checkPixel( 0, 0, 153, 153, 153, 153)); 842 EXPECT_TRUE(checkPixel(63, 0, 153, 153, 153, 153)); 843 EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153)); 844 EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153)); 845 846 EXPECT_TRUE(checkPixel( 4, 7, 255, 0, 0, 255)); 847 EXPECT_TRUE(checkPixel(25, 51, 0, 255, 0, 255)); 848 EXPECT_TRUE(checkPixel(40, 19, 0, 0, 255, 255)); 849 EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153)); 850 EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153)); 851 EXPECT_TRUE(checkPixel(13, 8, 153, 153, 153, 153)); 852 EXPECT_TRUE(checkPixel(46, 3, 153, 153, 153, 153)); 853 EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153)); 854 EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153)); 855 EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153)); 856 EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153)); 857 EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153)); 858 EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153)); 859 EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153)); 860 EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153)); 861 EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153)); 862} 863 864// Test to examine the actual encoding with GL buffers 865// Actual encoder, Actual GL Buffers Filled SurfaceMediaSource 866// The same pattern is rendered every frame 867TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaSameImageEachBufNpotWrite) { 868 ALOGV("Test # %d", testId++); 869 ALOGV("************** Testing the whole pipeline with actual Recorder ***********"); 870 ALOGV("************** GL Filling the buffers ***********"); 871 // Note: No need to set the colorformat for the buffers. The colorformat is 872 // in the GRAlloc buffers itself. 873 874 const char *fileName = "/sdcard/outputSurfEncMSourceGL.mp4"; 875 int fd = open(fileName, O_RDWR | O_CREAT, 0744); 876 if (fd < 0) { 877 ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd); 878 } 879 CHECK(fd >= 0); 880 881 sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE, 882 OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30); 883 884 // get the reference to the surfacemediasource living in 885 // mediaserver that is created by stagefrightrecorder 886 setUpEGLSurfaceFromMediaRecorder(mr); 887 888 int32_t nFramesCount = 0; 889 while (nFramesCount <= 300) { 890 oneBufferPassGL(); 891 nFramesCount++; 892 ALOGV("framesCount = %d", nFramesCount); 893 } 894 895 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, 896 EGL_NO_CONTEXT)); 897 ASSERT_EQ(EGL_SUCCESS, eglGetError()); 898 eglDestroySurface(mEglDisplay, mEglSurface); 899 mEglSurface = EGL_NO_SURFACE; 900 901 ALOGV("Stopping MediaRecorder..."); 902 CHECK_EQ((status_t)OK, mr->stop()); 903 mr.clear(); 904 close(fd); 905} 906 907// Test to examine the actual encoding from the GL Buffers 908// Actual encoder, Actual GL Buffers Filled SurfaceMediaSource 909// A different pattern is rendered every frame 910TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaDiffImageEachBufNpotWrite) { 911 ALOGV("Test # %d", testId++); 912 ALOGV("************** Testing the whole pipeline with actual Recorder ***********"); 913 ALOGV("************** Diff GL Filling the buffers ***********"); 914 // Note: No need to set the colorformat for the buffers. The colorformat is 915 // in the GRAlloc buffers itself. 916 917 const char *fileName = "/sdcard/outputSurfEncMSourceGLDiff.mp4"; 918 int fd = open(fileName, O_RDWR | O_CREAT, 0744); 919 if (fd < 0) { 920 ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd); 921 } 922 CHECK(fd >= 0); 923 924 sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE, 925 OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30); 926 927 // get the reference to the surfacemediasource living in 928 // mediaserver that is created by stagefrightrecorder 929 setUpEGLSurfaceFromMediaRecorder(mr); 930 931 int32_t nFramesCount = 0; 932 while (nFramesCount <= 300) { 933 oneBufferPassGL(nFramesCount); 934 nFramesCount++; 935 ALOGV("framesCount = %d", nFramesCount); 936 } 937 938 EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, 939 EGL_NO_CONTEXT)); 940 ASSERT_EQ(EGL_SUCCESS, eglGetError()); 941 eglDestroySurface(mEglDisplay, mEglSurface); 942 mEglSurface = EGL_NO_SURFACE; 943 944 ALOGV("Stopping MediaRecorder..."); 945 CHECK_EQ((status_t)OK, mr->stop()); 946 mr.clear(); 947 close(fd); 948} 949} // namespace android 950