1 /* 2 * Copyright (C) 2009 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 "SoftwareRenderer" 18 #include <utils/Log.h> 19 20 #include "../include/SoftwareRenderer.h" 21 22 #include <cutils/properties.h> // for property_get 23 #include <media/stagefright/foundation/ADebug.h> 24 #include <media/stagefright/foundation/AMessage.h> 25 #include <system/window.h> 26 #include <ui/GraphicBufferMapper.h> 27 #include <gui/IGraphicBufferProducer.h> 28 29 namespace android { 30 31 static bool runningInEmulator() { 32 char prop[PROPERTY_VALUE_MAX]; 33 return (property_get("ro.kernel.qemu", prop, NULL) > 0); 34 } 35 36 static int ALIGN(int x, int y) { 37 // y must be a power of 2. 38 return (x + y - 1) & ~(y - 1); 39 } 40 41 SoftwareRenderer::SoftwareRenderer( 42 const sp<ANativeWindow> &nativeWindow, int32_t rotation) 43 : mColorFormat(OMX_COLOR_FormatUnused), 44 mConverter(NULL), 45 mYUVMode(None), 46 mNativeWindow(nativeWindow), 47 mWidth(0), 48 mHeight(0), 49 mCropLeft(0), 50 mCropTop(0), 51 mCropRight(0), 52 mCropBottom(0), 53 mCropWidth(0), 54 mCropHeight(0), 55 mRotationDegrees(rotation) { 56 } 57 58 SoftwareRenderer::~SoftwareRenderer() { 59 delete mConverter; 60 mConverter = NULL; 61 } 62 63 void SoftwareRenderer::resetFormatIfChanged(const sp<AMessage> &format) { 64 CHECK(format != NULL); 65 66 int32_t colorFormatNew; 67 CHECK(format->findInt32("color-format", &colorFormatNew)); 68 69 int32_t widthNew, heightNew; 70 CHECK(format->findInt32("stride", &widthNew)); 71 CHECK(format->findInt32("slice-height", &heightNew)); 72 73 int32_t cropLeftNew, cropTopNew, cropRightNew, cropBottomNew; 74 if (!format->findRect( 75 "crop", &cropLeftNew, &cropTopNew, &cropRightNew, &cropBottomNew)) { 76 cropLeftNew = cropTopNew = 0; 77 cropRightNew = widthNew - 1; 78 cropBottomNew = heightNew - 1; 79 } 80 81 if (static_cast<int32_t>(mColorFormat) == colorFormatNew && 82 mWidth == widthNew && 83 mHeight == heightNew && 84 mCropLeft == cropLeftNew && 85 mCropTop == cropTopNew && 86 mCropRight == cropRightNew && 87 mCropBottom == cropBottomNew) { 88 // Nothing changed, no need to reset renderer. 89 return; 90 } 91 92 mColorFormat = static_cast<OMX_COLOR_FORMATTYPE>(colorFormatNew); 93 mWidth = widthNew; 94 mHeight = heightNew; 95 mCropLeft = cropLeftNew; 96 mCropTop = cropTopNew; 97 mCropRight = cropRightNew; 98 mCropBottom = cropBottomNew; 99 100 mCropWidth = mCropRight - mCropLeft + 1; 101 mCropHeight = mCropBottom - mCropTop + 1; 102 103 // by default convert everything to RGB565 104 int halFormat = HAL_PIXEL_FORMAT_RGB_565; 105 size_t bufWidth = mCropWidth; 106 size_t bufHeight = mCropHeight; 107 108 // hardware has YUV12 and RGBA8888 support, so convert known formats 109 if (!runningInEmulator()) { 110 switch (mColorFormat) { 111 case OMX_COLOR_FormatYUV420Planar: 112 case OMX_COLOR_FormatYUV420SemiPlanar: 113 case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: 114 { 115 halFormat = HAL_PIXEL_FORMAT_YV12; 116 bufWidth = (mCropWidth + 1) & ~1; 117 bufHeight = (mCropHeight + 1) & ~1; 118 break; 119 } 120 case OMX_COLOR_Format24bitRGB888: 121 { 122 halFormat = HAL_PIXEL_FORMAT_RGB_888; 123 bufWidth = (mCropWidth + 1) & ~1; 124 bufHeight = (mCropHeight + 1) & ~1; 125 break; 126 } 127 case OMX_COLOR_Format32bitARGB8888: 128 case OMX_COLOR_Format32BitRGBA8888: 129 { 130 halFormat = HAL_PIXEL_FORMAT_RGBA_8888; 131 bufWidth = (mCropWidth + 1) & ~1; 132 bufHeight = (mCropHeight + 1) & ~1; 133 break; 134 } 135 default: 136 { 137 break; 138 } 139 } 140 } 141 142 if (halFormat == HAL_PIXEL_FORMAT_RGB_565) { 143 mConverter = new ColorConverter( 144 mColorFormat, OMX_COLOR_Format16bitRGB565); 145 CHECK(mConverter->isValid()); 146 } 147 148 CHECK(mNativeWindow != NULL); 149 CHECK(mCropWidth > 0); 150 CHECK(mCropHeight > 0); 151 CHECK(mConverter == NULL || mConverter->isValid()); 152 153 CHECK_EQ(0, 154 native_window_set_usage( 155 mNativeWindow.get(), 156 GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN 157 | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP)); 158 159 CHECK_EQ(0, 160 native_window_set_scaling_mode( 161 mNativeWindow.get(), 162 NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)); 163 164 // Width must be multiple of 32??? 165 CHECK_EQ(0, native_window_set_buffers_dimensions( 166 mNativeWindow.get(), 167 bufWidth, 168 bufHeight)); 169 CHECK_EQ(0, native_window_set_buffers_format( 170 mNativeWindow.get(), 171 halFormat)); 172 173 // NOTE: native window uses extended right-bottom coordinate 174 android_native_rect_t crop; 175 crop.left = mCropLeft; 176 crop.top = mCropTop; 177 crop.right = mCropRight + 1; 178 crop.bottom = mCropBottom + 1; 179 ALOGV("setting crop: [%d, %d, %d, %d] for size [%zu, %zu]", 180 crop.left, crop.top, crop.right, crop.bottom, bufWidth, bufHeight); 181 182 CHECK_EQ(0, native_window_set_crop(mNativeWindow.get(), &crop)); 183 184 int32_t rotationDegrees; 185 if (!format->findInt32("rotation-degrees", &rotationDegrees)) { 186 rotationDegrees = mRotationDegrees; 187 } 188 uint32_t transform; 189 switch (rotationDegrees) { 190 case 0: transform = 0; break; 191 case 90: transform = HAL_TRANSFORM_ROT_90; break; 192 case 180: transform = HAL_TRANSFORM_ROT_180; break; 193 case 270: transform = HAL_TRANSFORM_ROT_270; break; 194 default: transform = 0; break; 195 } 196 197 CHECK_EQ(0, native_window_set_buffers_transform( 198 mNativeWindow.get(), transform)); 199 } 200 201 void SoftwareRenderer::clearTracker() { 202 mRenderTracker.clear(-1 /* lastRenderTimeNs */); 203 } 204 205 std::list<FrameRenderTracker::Info> SoftwareRenderer::render( 206 const void *data, size_t size, int64_t mediaTimeUs, nsecs_t renderTimeNs, 207 void* /*platformPrivate*/, const sp<AMessage>& format) { 208 resetFormatIfChanged(format); 209 FrameRenderTracker::Info *info = NULL; 210 211 ANativeWindowBuffer *buf; 212 int fenceFd = -1; 213 int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd); 214 if (err == 0 && fenceFd >= 0) { 215 info = mRenderTracker.updateInfoForDequeuedBuffer(buf, fenceFd, 0); 216 sp<Fence> fence = new Fence(fenceFd); 217 err = fence->waitForever("SoftwareRenderer::render"); 218 } 219 if (err != 0) { 220 ALOGW("Surface::dequeueBuffer returned error %d", err); 221 // complete (drop) dequeued frame if fence wait failed; otherwise, 222 // this returns an empty list as no frames should have rendered and not yet returned. 223 return mRenderTracker.checkFencesAndGetRenderedFrames(info, false /* dropIncomplete */); 224 } 225 226 GraphicBufferMapper &mapper = GraphicBufferMapper::get(); 227 228 Rect bounds(mCropWidth, mCropHeight); 229 230 void *dst; 231 CHECK_EQ(0, mapper.lock( 232 buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst)); 233 234 // TODO move the other conversions also into ColorConverter, and 235 // fix cropping issues (when mCropLeft/Top != 0 or mWidth != mCropWidth) 236 if (mConverter) { 237 mConverter->convert( 238 data, 239 mWidth, mHeight, 240 mCropLeft, mCropTop, mCropRight, mCropBottom, 241 dst, 242 buf->stride, buf->height, 243 0, 0, mCropWidth - 1, mCropHeight - 1); 244 } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) { 245 if ((size_t)mWidth * mHeight * 3 / 2 > size) { 246 goto skip_copying; 247 } 248 const uint8_t *src_y = (const uint8_t *)data; 249 const uint8_t *src_u = 250 (const uint8_t *)data + mWidth * mHeight; 251 const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2); 252 253 uint8_t *dst_y = (uint8_t *)dst; 254 size_t dst_y_size = buf->stride * buf->height; 255 size_t dst_c_stride = ALIGN(buf->stride / 2, 16); 256 size_t dst_c_size = dst_c_stride * buf->height / 2; 257 uint8_t *dst_v = dst_y + dst_y_size; 258 uint8_t *dst_u = dst_v + dst_c_size; 259 260 for (int y = 0; y < mCropHeight; ++y) { 261 memcpy(dst_y, src_y, mCropWidth); 262 263 src_y += mWidth; 264 dst_y += buf->stride; 265 } 266 267 for (int y = 0; y < (mCropHeight + 1) / 2; ++y) { 268 memcpy(dst_u, src_u, (mCropWidth + 1) / 2); 269 memcpy(dst_v, src_v, (mCropWidth + 1) / 2); 270 271 src_u += mWidth / 2; 272 src_v += mWidth / 2; 273 dst_u += dst_c_stride; 274 dst_v += dst_c_stride; 275 } 276 } else if (mColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar 277 || mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { 278 if ((size_t)mWidth * mHeight * 3 / 2 > size) { 279 goto skip_copying; 280 } 281 const uint8_t *src_y = (const uint8_t *)data; 282 const uint8_t *src_uv = (const uint8_t *)data 283 + mWidth * (mHeight - mCropTop / 2); 284 285 uint8_t *dst_y = (uint8_t *)dst; 286 287 size_t dst_y_size = buf->stride * buf->height; 288 size_t dst_c_stride = ALIGN(buf->stride / 2, 16); 289 size_t dst_c_size = dst_c_stride * buf->height / 2; 290 uint8_t *dst_v = dst_y + dst_y_size; 291 uint8_t *dst_u = dst_v + dst_c_size; 292 293 for (int y = 0; y < mCropHeight; ++y) { 294 memcpy(dst_y, src_y, mCropWidth); 295 296 src_y += mWidth; 297 dst_y += buf->stride; 298 } 299 300 for (int y = 0; y < (mCropHeight + 1) / 2; ++y) { 301 size_t tmp = (mCropWidth + 1) / 2; 302 for (size_t x = 0; x < tmp; ++x) { 303 dst_u[x] = src_uv[2 * x]; 304 dst_v[x] = src_uv[2 * x + 1]; 305 } 306 307 src_uv += mWidth; 308 dst_u += dst_c_stride; 309 dst_v += dst_c_stride; 310 } 311 } else if (mColorFormat == OMX_COLOR_Format24bitRGB888) { 312 if ((size_t)mWidth * mHeight * 3 > size) { 313 goto skip_copying; 314 } 315 uint8_t* srcPtr = (uint8_t*)data; 316 uint8_t* dstPtr = (uint8_t*)dst; 317 318 for (size_t y = 0; y < (size_t)mCropHeight; ++y) { 319 memcpy(dstPtr, srcPtr, mCropWidth * 3); 320 srcPtr += mWidth * 3; 321 dstPtr += buf->stride * 3; 322 } 323 } else if (mColorFormat == OMX_COLOR_Format32bitARGB8888) { 324 if ((size_t)mWidth * mHeight * 4 > size) { 325 goto skip_copying; 326 } 327 uint8_t *srcPtr, *dstPtr; 328 329 for (size_t y = 0; y < (size_t)mCropHeight; ++y) { 330 srcPtr = (uint8_t*)data + mWidth * 4 * y; 331 dstPtr = (uint8_t*)dst + buf->stride * 4 * y; 332 for (size_t x = 0; x < (size_t)mCropWidth; ++x) { 333 uint8_t a = *srcPtr++; 334 for (size_t i = 0; i < 3; ++i) { // copy RGB 335 *dstPtr++ = *srcPtr++; 336 } 337 *dstPtr++ = a; // alpha last (ARGB to RGBA) 338 } 339 } 340 } else if (mColorFormat == OMX_COLOR_Format32BitRGBA8888) { 341 if ((size_t)mWidth * mHeight * 4 > size) { 342 goto skip_copying; 343 } 344 uint8_t* srcPtr = (uint8_t*)data; 345 uint8_t* dstPtr = (uint8_t*)dst; 346 347 for (size_t y = 0; y < (size_t)mCropHeight; ++y) { 348 memcpy(dstPtr, srcPtr, mCropWidth * 4); 349 srcPtr += mWidth * 4; 350 dstPtr += buf->stride * 4; 351 } 352 } else { 353 LOG_ALWAYS_FATAL("bad color format %#x", mColorFormat); 354 } 355 356 skip_copying: 357 CHECK_EQ(0, mapper.unlock(buf->handle)); 358 359 if (renderTimeNs >= 0) { 360 if ((err = native_window_set_buffers_timestamp(mNativeWindow.get(), 361 renderTimeNs)) != 0) { 362 ALOGW("Surface::set_buffers_timestamp returned error %d", err); 363 } 364 } 365 366 // TODO: propagate color aspects to software renderer to allow better 367 // color conversion to RGB. For now, just mark dataspace for YUV rendering. 368 android_dataspace dataSpace; 369 if (format->findInt32("android._dataspace", (int32_t *)&dataSpace) && dataSpace != mDataSpace) { 370 ALOGD("setting dataspace on output surface to #%x", dataSpace); 371 if ((err = native_window_set_buffers_data_space(mNativeWindow.get(), dataSpace))) { 372 ALOGW("failed to set dataspace on surface (%d)", err); 373 } 374 mDataSpace = dataSpace; 375 } 376 if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf, -1)) != 0) { 377 ALOGW("Surface::queueBuffer returned error %d", err); 378 } else { 379 mRenderTracker.onFrameQueued(mediaTimeUs, (GraphicBuffer *)buf, Fence::NO_FENCE); 380 } 381 382 buf = NULL; 383 return mRenderTracker.checkFencesAndGetRenderedFrames(info, info != NULL /* dropIncomplete */); 384 } 385 386 } // namespace android 387