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