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_TAG "NativeWindowRenderer" 18 #include "NativeWindowRenderer.h" 19 20 #include <GLES2/gl2.h> 21 #include <GLES2/gl2ext.h> 22 #include <cutils/log.h> 23 #include <gui/SurfaceTexture.h> 24 #include <gui/SurfaceTextureClient.h> 25 #include <stagefright/MediaBuffer.h> 26 #include <stagefright/MediaDebug.h> 27 #include <stagefright/MetaData.h> 28 #include <surfaceflinger/Surface.h> 29 #include "VideoEditorTools.h" 30 31 #define CHECK_EGL_ERROR CHECK(EGL_SUCCESS == eglGetError()) 32 #define CHECK_GL_ERROR CHECK(GLenum(GL_NO_ERROR) == glGetError()) 33 34 // 35 // Vertex and fragment programs 36 // 37 38 // The matrix is derived from 39 // frameworks/base/media/libstagefright/colorconversion/ColorConverter.cpp 40 // 41 // R * 255 = 1.164 * (Y - 16) + 1.596 * (V - 128) 42 // G * 255 = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128) 43 // B * 255 = 1.164 * (Y - 16) + 2.018 * (U - 128) 44 // 45 // Here we assume YUV are in the range of [0,255], RGB are in the range of 46 // [0, 1] 47 #define RGB2YUV_MATRIX \ 48 "const mat4 rgb2yuv = mat4("\ 49 " 65.52255, -37.79398, 111.98732, 0.00000,"\ 50 " 128.62729, -74.19334, -93.81088, 0.00000,"\ 51 " 24.92233, 111.98732, -18.17644, 0.00000,"\ 52 " 16.00000, 128.00000, 128.00000, 1.00000);\n" 53 54 #define YUV2RGB_MATRIX \ 55 "const mat4 yuv2rgb = mat4("\ 56 " 0.00456, 0.00456, 0.00456, 0.00000,"\ 57 " 0.00000, -0.00153, 0.00791, 0.00000,"\ 58 " 0.00626, -0.00319, 0.00000, 0.00000,"\ 59 " -0.87416, 0.53133, -1.08599, 1.00000);\n" 60 61 static const char vSrcNormal[] = 62 "attribute vec4 vPosition;\n" 63 "attribute vec2 vTexPos;\n" 64 "uniform mat4 texMatrix;\n" 65 "varying vec2 texCoords;\n" 66 "varying float topDown;\n" 67 "void main() {\n" 68 " gl_Position = vPosition;\n" 69 " texCoords = (texMatrix * vec4(vTexPos, 0.0, 1.0)).xy;\n" 70 " topDown = vTexPos.y;\n" 71 "}\n"; 72 73 static const char fSrcNormal[] = 74 "#extension GL_OES_EGL_image_external : require\n" 75 "precision mediump float;\n" 76 "uniform samplerExternalOES texSampler;\n" 77 "varying vec2 texCoords;\n" 78 "void main() {\n" 79 " gl_FragColor = texture2D(texSampler, texCoords);\n" 80 "}\n"; 81 82 static const char fSrcSepia[] = 83 "#extension GL_OES_EGL_image_external : require\n" 84 "precision mediump float;\n" 85 "uniform samplerExternalOES texSampler;\n" 86 "varying vec2 texCoords;\n" 87 RGB2YUV_MATRIX 88 YUV2RGB_MATRIX 89 "void main() {\n" 90 " vec4 rgb = texture2D(texSampler, texCoords);\n" 91 " vec4 yuv = rgb2yuv * rgb;\n" 92 " yuv = vec4(yuv.x, 117.0, 139.0, 1.0);\n" 93 " gl_FragColor = yuv2rgb * yuv;\n" 94 "}\n"; 95 96 static const char fSrcNegative[] = 97 "#extension GL_OES_EGL_image_external : require\n" 98 "precision mediump float;\n" 99 "uniform samplerExternalOES texSampler;\n" 100 "varying vec2 texCoords;\n" 101 RGB2YUV_MATRIX 102 YUV2RGB_MATRIX 103 "void main() {\n" 104 " vec4 rgb = texture2D(texSampler, texCoords);\n" 105 " vec4 yuv = rgb2yuv * rgb;\n" 106 " yuv = vec4(255.0 - yuv.x, yuv.y, yuv.z, 1.0);\n" 107 " gl_FragColor = yuv2rgb * yuv;\n" 108 "}\n"; 109 110 static const char fSrcGradient[] = 111 "#extension GL_OES_EGL_image_external : require\n" 112 "precision mediump float;\n" 113 "uniform samplerExternalOES texSampler;\n" 114 "varying vec2 texCoords;\n" 115 "varying float topDown;\n" 116 RGB2YUV_MATRIX 117 YUV2RGB_MATRIX 118 "void main() {\n" 119 " vec4 rgb = texture2D(texSampler, texCoords);\n" 120 " vec4 yuv = rgb2yuv * rgb;\n" 121 " vec4 mixin = vec4(15.0/31.0, 59.0/63.0, 31.0/31.0, 1.0);\n" 122 " vec4 yuv2 = rgb2yuv * vec4((mixin.xyz * topDown), 1);\n" 123 " yuv = vec4(yuv.x, yuv2.y, yuv2.z, 1);\n" 124 " gl_FragColor = yuv2rgb * yuv;\n" 125 "}\n"; 126 127 namespace android { 128 129 NativeWindowRenderer::NativeWindowRenderer(sp<ANativeWindow> nativeWindow, 130 int width, int height) 131 : mNativeWindow(nativeWindow) 132 , mDstWidth(width) 133 , mDstHeight(height) 134 , mLastVideoEffect(-1) 135 , mNextTextureId(100) 136 , mActiveInputs(0) 137 , mThreadCmd(CMD_IDLE) { 138 createThread(threadStart, this); 139 } 140 141 // The functions below run in the GL thread. 142 // 143 // All GL-related work is done in this thread, and other threads send 144 // requests to this thread using a command code. We expect most of the 145 // time there will only be one thread sending in requests, so we let 146 // other threads wait until the request is finished by GL thread. 147 148 int NativeWindowRenderer::threadStart(void* self) { 149 LOGD("create thread"); 150 ((NativeWindowRenderer*)self)->glThread(); 151 return 0; 152 } 153 154 void NativeWindowRenderer::glThread() { 155 initializeEGL(); 156 createPrograms(); 157 158 Mutex::Autolock autoLock(mLock); 159 bool quit = false; 160 while (!quit) { 161 switch (mThreadCmd) { 162 case CMD_IDLE: 163 mCond.wait(mLock); 164 continue; 165 case CMD_RENDER_INPUT: 166 render(mThreadRenderInput); 167 break; 168 case CMD_RESERVE_TEXTURE: 169 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mThreadTextureId); 170 CHECK_GL_ERROR; 171 break; 172 case CMD_DELETE_TEXTURE: 173 glDeleteTextures(1, &mThreadTextureId); 174 break; 175 case CMD_QUIT: 176 terminateEGL(); 177 quit = true; 178 break; 179 } 180 // Tell the requester that the command is finished. 181 mThreadCmd = CMD_IDLE; 182 mCond.broadcast(); 183 } 184 LOGD("quit"); 185 } 186 187 void NativeWindowRenderer::initializeEGL() { 188 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); 189 CHECK_EGL_ERROR; 190 191 EGLint majorVersion; 192 EGLint minorVersion; 193 eglInitialize(mEglDisplay, &majorVersion, &minorVersion); 194 CHECK_EGL_ERROR; 195 196 EGLConfig config; 197 EGLint numConfigs = -1; 198 EGLint configAttribs[] = { 199 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 200 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 201 EGL_RED_SIZE, 8, 202 EGL_GREEN_SIZE, 8, 203 EGL_BLUE_SIZE, 8, 204 EGL_NONE 205 }; 206 eglChooseConfig(mEglDisplay, configAttribs, &config, 1, &numConfigs); 207 CHECK_EGL_ERROR; 208 209 mEglSurface = eglCreateWindowSurface(mEglDisplay, config, 210 mNativeWindow.get(), NULL); 211 CHECK_EGL_ERROR; 212 213 EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 214 mEglContext = eglCreateContext(mEglDisplay, config, EGL_NO_CONTEXT, 215 contextAttribs); 216 CHECK_EGL_ERROR; 217 218 eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); 219 CHECK_EGL_ERROR; 220 } 221 222 void NativeWindowRenderer::terminateEGL() { 223 eglDestroyContext(mEglDisplay, mEglContext); 224 eglDestroySurface(mEglDisplay, mEglSurface); 225 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 226 eglTerminate(mEglDisplay); 227 } 228 229 void NativeWindowRenderer::createPrograms() { 230 GLuint vShader; 231 loadShader(GL_VERTEX_SHADER, vSrcNormal, &vShader); 232 233 const char* fSrc[NUMBER_OF_EFFECTS] = { 234 fSrcNormal, fSrcSepia, fSrcNegative, fSrcGradient 235 }; 236 237 for (int i = 0; i < NUMBER_OF_EFFECTS; i++) { 238 GLuint fShader; 239 loadShader(GL_FRAGMENT_SHADER, fSrc[i], &fShader); 240 createProgram(vShader, fShader, &mProgram[i]); 241 glDeleteShader(fShader); 242 CHECK_GL_ERROR; 243 } 244 245 glDeleteShader(vShader); 246 CHECK_GL_ERROR; 247 } 248 249 void NativeWindowRenderer::createProgram( 250 GLuint vertexShader, GLuint fragmentShader, GLuint* outPgm) { 251 252 GLuint program = glCreateProgram(); 253 CHECK_GL_ERROR; 254 255 glAttachShader(program, vertexShader); 256 CHECK_GL_ERROR; 257 258 glAttachShader(program, fragmentShader); 259 CHECK_GL_ERROR; 260 261 glLinkProgram(program); 262 CHECK_GL_ERROR; 263 264 GLint linkStatus = GL_FALSE; 265 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 266 if (linkStatus != GL_TRUE) { 267 GLint infoLen = 0; 268 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen); 269 if (infoLen) { 270 char* buf = (char*) malloc(infoLen); 271 if (buf) { 272 glGetProgramInfoLog(program, infoLen, NULL, buf); 273 LOGE("Program link log:\n%s\n", buf); 274 free(buf); 275 } 276 } 277 glDeleteProgram(program); 278 program = 0; 279 } 280 281 *outPgm = program; 282 } 283 284 void NativeWindowRenderer::loadShader(GLenum shaderType, const char* pSource, 285 GLuint* outShader) { 286 GLuint shader = glCreateShader(shaderType); 287 CHECK_GL_ERROR; 288 289 glShaderSource(shader, 1, &pSource, NULL); 290 CHECK_GL_ERROR; 291 292 glCompileShader(shader); 293 CHECK_GL_ERROR; 294 295 GLint compiled = 0; 296 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 297 if (!compiled) { 298 GLint infoLen = 0; 299 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 300 char* buf = (char*) malloc(infoLen); 301 if (buf) { 302 glGetShaderInfoLog(shader, infoLen, NULL, buf); 303 LOGE("Shader compile log:\n%s\n", buf); 304 free(buf); 305 } 306 glDeleteShader(shader); 307 shader = 0; 308 } 309 *outShader = shader; 310 } 311 312 NativeWindowRenderer::~NativeWindowRenderer() { 313 CHECK(mActiveInputs == 0); 314 startRequest(CMD_QUIT); 315 sendRequest(); 316 } 317 318 void NativeWindowRenderer::render(RenderInput* input) { 319 sp<SurfaceTexture> ST = input->mST; 320 sp<SurfaceTextureClient> STC = input->mSTC; 321 322 if (input->mIsExternalBuffer) { 323 queueExternalBuffer(STC.get(), input->mBuffer, 324 input->mWidth, input->mHeight); 325 } else { 326 queueInternalBuffer(STC.get(), input->mBuffer); 327 } 328 329 ST->updateTexImage(); 330 glClearColor(0, 0, 0, 0); 331 glClear(GL_COLOR_BUFFER_BIT); 332 333 calculatePositionCoordinates(input->mRenderingMode, 334 input->mWidth, input->mHeight); 335 336 const GLfloat textureCoordinates[] = { 337 0.0f, 1.0f, 338 0.0f, 0.0f, 339 1.0f, 0.0f, 340 1.0f, 1.0f, 341 }; 342 343 updateProgramAndHandle(input->mVideoEffect); 344 345 glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, 346 mPositionCoordinates); 347 CHECK_GL_ERROR; 348 349 glEnableVertexAttribArray(mPositionHandle); 350 CHECK_GL_ERROR; 351 352 glVertexAttribPointer(mTexPosHandle, 2, GL_FLOAT, GL_FALSE, 0, 353 textureCoordinates); 354 CHECK_GL_ERROR; 355 356 glEnableVertexAttribArray(mTexPosHandle); 357 CHECK_GL_ERROR; 358 359 GLfloat texMatrix[16]; 360 ST->getTransformMatrix(texMatrix); 361 glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix); 362 CHECK_GL_ERROR; 363 364 glBindTexture(GL_TEXTURE_EXTERNAL_OES, input->mTextureId); 365 CHECK_GL_ERROR; 366 367 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 368 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 369 glTexParameteri( 370 GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 371 glTexParameteri( 372 GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 373 CHECK_GL_ERROR; 374 375 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 376 CHECK_GL_ERROR; 377 378 eglSwapBuffers(mEglDisplay, mEglSurface); 379 } 380 381 void NativeWindowRenderer::queueInternalBuffer(ANativeWindow *anw, 382 MediaBuffer* buffer) { 383 int64_t timeUs; 384 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); 385 native_window_set_buffers_timestamp(anw, timeUs * 1000); 386 status_t err = anw->queueBuffer(anw, buffer->graphicBuffer().get()); 387 if (err != 0) { 388 LOGE("queueBuffer failed with error %s (%d)", strerror(-err), -err); 389 return; 390 } 391 392 sp<MetaData> metaData = buffer->meta_data(); 393 metaData->setInt32(kKeyRendered, 1); 394 } 395 396 void NativeWindowRenderer::queueExternalBuffer(ANativeWindow* anw, 397 MediaBuffer* buffer, int width, int height) { 398 native_window_set_buffers_geometry(anw, width, height, 399 HAL_PIXEL_FORMAT_YV12); 400 native_window_set_usage(anw, GRALLOC_USAGE_SW_WRITE_OFTEN); 401 402 ANativeWindowBuffer* anb; 403 anw->dequeueBuffer(anw, &anb); 404 CHECK(anb != NULL); 405 406 sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); 407 CHECK(NO_ERROR == anw->lockBuffer(anw, buf->getNativeBuffer())); 408 409 // Copy the buffer 410 uint8_t* img = NULL; 411 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 412 copyI420Buffer(buffer, img, width, height, buf->getStride()); 413 buf->unlock(); 414 CHECK(NO_ERROR == anw->queueBuffer(anw, buf->getNativeBuffer())); 415 } 416 417 void NativeWindowRenderer::copyI420Buffer(MediaBuffer* src, uint8_t* dst, 418 int srcWidth, int srcHeight, int stride) { 419 int strideUV = (stride / 2 + 0xf) & ~0xf; 420 uint8_t* p = (uint8_t*)src->data() + src->range_offset(); 421 // Y 422 for (int i = srcHeight; i > 0; i--) { 423 memcpy(dst, p, srcWidth); 424 dst += stride; 425 p += srcWidth; 426 } 427 // The src is I420, the dst is YV12. 428 // U 429 p += srcWidth * srcHeight / 4; 430 for (int i = srcHeight / 2; i > 0; i--) { 431 memcpy(dst, p, srcWidth / 2); 432 dst += strideUV; 433 p += srcWidth / 2; 434 } 435 // V 436 p -= srcWidth * srcHeight / 2; 437 for (int i = srcHeight / 2; i > 0; i--) { 438 memcpy(dst, p, srcWidth / 2); 439 dst += strideUV; 440 p += srcWidth / 2; 441 } 442 } 443 444 void NativeWindowRenderer::updateProgramAndHandle(uint32_t videoEffect) { 445 if (mLastVideoEffect == videoEffect) { 446 return; 447 } 448 449 mLastVideoEffect = videoEffect; 450 int i; 451 switch (mLastVideoEffect) { 452 case VIDEO_EFFECT_NONE: 453 i = 0; 454 break; 455 case VIDEO_EFFECT_SEPIA: 456 i = 1; 457 break; 458 case VIDEO_EFFECT_NEGATIVE: 459 i = 2; 460 break; 461 case VIDEO_EFFECT_GRADIENT: 462 i = 3; 463 break; 464 default: 465 i = 0; 466 break; 467 } 468 glUseProgram(mProgram[i]); 469 CHECK_GL_ERROR; 470 471 mPositionHandle = glGetAttribLocation(mProgram[i], "vPosition"); 472 mTexPosHandle = glGetAttribLocation(mProgram[i], "vTexPos"); 473 mTexMatrixHandle = glGetUniformLocation(mProgram[i], "texMatrix"); 474 CHECK_GL_ERROR; 475 } 476 477 void NativeWindowRenderer::calculatePositionCoordinates( 478 M4xVSS_MediaRendering renderingMode, int srcWidth, int srcHeight) { 479 float x, y; 480 switch (renderingMode) { 481 case M4xVSS_kResizing: 482 default: 483 x = 1; 484 y = 1; 485 break; 486 case M4xVSS_kCropping: 487 x = float(srcWidth) / mDstWidth; 488 y = float(srcHeight) / mDstHeight; 489 // Make the smaller side 1 490 if (x > y) { 491 x /= y; 492 y = 1; 493 } else { 494 y /= x; 495 x = 1; 496 } 497 break; 498 case M4xVSS_kBlackBorders: 499 x = float(srcWidth) / mDstWidth; 500 y = float(srcHeight) / mDstHeight; 501 // Make the larger side 1 502 if (x > y) { 503 y /= x; 504 x = 1; 505 } else { 506 x /= y; 507 y = 1; 508 } 509 break; 510 } 511 512 mPositionCoordinates[0] = -x; 513 mPositionCoordinates[1] = y; 514 mPositionCoordinates[2] = -x; 515 mPositionCoordinates[3] = -y; 516 mPositionCoordinates[4] = x; 517 mPositionCoordinates[5] = -y; 518 mPositionCoordinates[6] = x; 519 mPositionCoordinates[7] = y; 520 } 521 522 // 523 // The functions below run in other threads. 524 // 525 526 void NativeWindowRenderer::startRequest(int cmd) { 527 mLock.lock(); 528 while (mThreadCmd != CMD_IDLE) { 529 mCond.wait(mLock); 530 } 531 mThreadCmd = cmd; 532 } 533 534 void NativeWindowRenderer::sendRequest() { 535 mCond.broadcast(); 536 while (mThreadCmd != CMD_IDLE) { 537 mCond.wait(mLock); 538 } 539 mLock.unlock(); 540 } 541 542 RenderInput* NativeWindowRenderer::createRenderInput() { 543 LOGD("new render input %d", mNextTextureId); 544 RenderInput* input = new RenderInput(this, mNextTextureId); 545 546 startRequest(CMD_RESERVE_TEXTURE); 547 mThreadTextureId = mNextTextureId; 548 sendRequest(); 549 550 mNextTextureId++; 551 mActiveInputs++; 552 return input; 553 } 554 555 void NativeWindowRenderer::destroyRenderInput(RenderInput* input) { 556 LOGD("destroy render input %d", input->mTextureId); 557 GLuint textureId = input->mTextureId; 558 delete input; 559 560 startRequest(CMD_DELETE_TEXTURE); 561 mThreadTextureId = textureId; 562 sendRequest(); 563 564 mActiveInputs--; 565 } 566 567 // 568 // RenderInput 569 // 570 571 RenderInput::RenderInput(NativeWindowRenderer* renderer, GLuint textureId) 572 : mRenderer(renderer) 573 , mTextureId(textureId) { 574 mST = new SurfaceTexture(mTextureId); 575 uint32_t outWidth, outHeight, outTransform; 576 mST->connect(NATIVE_WINDOW_API_MEDIA, &outWidth, &outHeight, &outTransform); 577 578 mSTC = new SurfaceTextureClient(mST); 579 } 580 581 RenderInput::~RenderInput() { 582 } 583 584 ANativeWindow* RenderInput::getTargetWindow() { 585 return mSTC.get(); 586 } 587 588 void RenderInput::updateVideoSize(sp<MetaData> meta) { 589 CHECK(meta->findInt32(kKeyWidth, &mWidth)); 590 CHECK(meta->findInt32(kKeyHeight, &mHeight)); 591 592 int left, top, right, bottom; 593 if (meta->findRect(kKeyCropRect, &left, &top, &right, &bottom)) { 594 mWidth = right - left + 1; 595 mHeight = bottom - top + 1; 596 } 597 598 // If rotation degrees is 90 or 270, swap width and height 599 // (mWidth and mHeight are the _rotated_ source rectangle). 600 int32_t rotationDegrees; 601 if (!meta->findInt32(kKeyRotation, &rotationDegrees)) { 602 rotationDegrees = 0; 603 } 604 605 if (rotationDegrees == 90 || rotationDegrees == 270) { 606 int tmp = mWidth; 607 mWidth = mHeight; 608 mHeight = tmp; 609 } 610 } 611 612 void RenderInput::render(MediaBuffer* buffer, uint32_t videoEffect, 613 M4xVSS_MediaRendering renderingMode, bool isExternalBuffer) { 614 mVideoEffect = videoEffect; 615 mRenderingMode = renderingMode; 616 mIsExternalBuffer = isExternalBuffer; 617 mBuffer = buffer; 618 619 mRenderer->startRequest(NativeWindowRenderer::CMD_RENDER_INPUT); 620 mRenderer->mThreadRenderInput = this; 621 mRenderer->sendRequest(); 622 } 623 624 } // namespace android 625