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