Home | History | Annotate | Download | only in colorconversion
      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 <binder/MemoryHeapBase.h>
     23 #include <binder/MemoryHeapPmem.h>
     24 #include <media/stagefright/foundation/ADebug.h>
     25 #include <media/stagefright/MetaData.h>
     26 #include <surfaceflinger/Surface.h>
     27 #include <ui/android_native_buffer.h>
     28 #include <ui/GraphicBufferMapper.h>
     29 #include <gui/ISurfaceTexture.h>
     30 
     31 namespace android {
     32 
     33 SoftwareRenderer::SoftwareRenderer(
     34         const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
     35     : mConverter(NULL),
     36       mYUVMode(None),
     37       mNativeWindow(nativeWindow) {
     38     int32_t tmp;
     39     CHECK(meta->findInt32(kKeyColorFormat, &tmp));
     40     mColorFormat = (OMX_COLOR_FORMATTYPE)tmp;
     41 
     42     CHECK(meta->findInt32(kKeyWidth, &mWidth));
     43     CHECK(meta->findInt32(kKeyHeight, &mHeight));
     44 
     45     if (!meta->findRect(
     46                 kKeyCropRect,
     47                 &mCropLeft, &mCropTop, &mCropRight, &mCropBottom)) {
     48         mCropLeft = mCropTop = 0;
     49         mCropRight = mWidth - 1;
     50         mCropBottom = mHeight - 1;
     51     }
     52 
     53     mCropWidth = mCropRight - mCropLeft + 1;
     54     mCropHeight = mCropBottom - mCropTop + 1;
     55 
     56     int32_t rotationDegrees;
     57     if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
     58         rotationDegrees = 0;
     59     }
     60 
     61     int halFormat;
     62     size_t bufWidth, bufHeight;
     63 
     64     switch (mColorFormat) {
     65         case OMX_COLOR_FormatYUV420Planar:
     66         case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
     67         {
     68             halFormat = HAL_PIXEL_FORMAT_YV12;
     69             bufWidth = (mCropWidth + 1) & ~1;
     70             bufHeight = (mCropHeight + 1) & ~1;
     71             break;
     72         }
     73 
     74         default:
     75             halFormat = HAL_PIXEL_FORMAT_RGB_565;
     76             bufWidth = mCropWidth;
     77             bufHeight = mCropHeight;
     78 
     79             mConverter = new ColorConverter(
     80                     mColorFormat, OMX_COLOR_Format16bitRGB565);
     81             CHECK(mConverter->isValid());
     82             break;
     83     }
     84 
     85     CHECK(mNativeWindow != NULL);
     86     CHECK(mCropWidth > 0);
     87     CHECK(mCropHeight > 0);
     88     CHECK(mConverter == NULL || mConverter->isValid());
     89 
     90     CHECK_EQ(0,
     91             native_window_set_usage(
     92             mNativeWindow.get(),
     93             GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
     94             | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
     95 
     96     CHECK_EQ(0,
     97             native_window_set_scaling_mode(
     98             mNativeWindow.get(),
     99             NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
    100 
    101     // Width must be multiple of 32???
    102     CHECK_EQ(0, native_window_set_buffers_geometry(
    103                 mNativeWindow.get(),
    104                 bufWidth,
    105                 bufHeight,
    106                 halFormat));
    107 
    108     uint32_t transform;
    109     switch (rotationDegrees) {
    110         case 0: transform = 0; break;
    111         case 90: transform = HAL_TRANSFORM_ROT_90; break;
    112         case 180: transform = HAL_TRANSFORM_ROT_180; break;
    113         case 270: transform = HAL_TRANSFORM_ROT_270; break;
    114         default: transform = 0; break;
    115     }
    116 
    117     if (transform) {
    118         CHECK_EQ(0, native_window_set_buffers_transform(
    119                     mNativeWindow.get(), transform));
    120     }
    121 }
    122 
    123 SoftwareRenderer::~SoftwareRenderer() {
    124     delete mConverter;
    125     mConverter = NULL;
    126 }
    127 
    128 static int ALIGN(int x, int y) {
    129     // y must be a power of 2.
    130     return (x + y - 1) & ~(y - 1);
    131 }
    132 
    133 void SoftwareRenderer::render(
    134         const void *data, size_t size, void *platformPrivate) {
    135     ANativeWindowBuffer *buf;
    136     int err;
    137     if ((err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf)) != 0) {
    138         LOGW("Surface::dequeueBuffer returned error %d", err);
    139         return;
    140     }
    141 
    142     CHECK_EQ(0, mNativeWindow->lockBuffer(mNativeWindow.get(), buf));
    143 
    144     GraphicBufferMapper &mapper = GraphicBufferMapper::get();
    145 
    146     Rect bounds(mCropWidth, mCropHeight);
    147 
    148     void *dst;
    149     CHECK_EQ(0, mapper.lock(
    150                 buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
    151 
    152     if (mConverter) {
    153         mConverter->convert(
    154                 data,
    155                 mWidth, mHeight,
    156                 mCropLeft, mCropTop, mCropRight, mCropBottom,
    157                 dst,
    158                 buf->stride, buf->height,
    159                 0, 0, mCropWidth - 1, mCropHeight - 1);
    160     } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
    161         const uint8_t *src_y = (const uint8_t *)data;
    162         const uint8_t *src_u = (const uint8_t *)data + mWidth * mHeight;
    163         const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
    164 
    165         uint8_t *dst_y = (uint8_t *)dst;
    166         size_t dst_y_size = buf->stride * buf->height;
    167         size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
    168         size_t dst_c_size = dst_c_stride * buf->height / 2;
    169         uint8_t *dst_v = dst_y + dst_y_size;
    170         uint8_t *dst_u = dst_v + dst_c_size;
    171 
    172         for (int y = 0; y < mCropHeight; ++y) {
    173             memcpy(dst_y, src_y, mCropWidth);
    174 
    175             src_y += mWidth;
    176             dst_y += buf->stride;
    177         }
    178 
    179         for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
    180             memcpy(dst_u, src_u, (mCropWidth + 1) / 2);
    181             memcpy(dst_v, src_v, (mCropWidth + 1) / 2);
    182 
    183             src_u += mWidth / 2;
    184             src_v += mWidth / 2;
    185             dst_u += dst_c_stride;
    186             dst_v += dst_c_stride;
    187         }
    188     } else {
    189         CHECK_EQ(mColorFormat, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar);
    190 
    191         const uint8_t *src_y =
    192             (const uint8_t *)data;
    193 
    194         const uint8_t *src_uv =
    195             (const uint8_t *)data + mWidth * (mHeight - mCropTop / 2);
    196 
    197         uint8_t *dst_y = (uint8_t *)dst;
    198 
    199         size_t dst_y_size = buf->stride * buf->height;
    200         size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
    201         size_t dst_c_size = dst_c_stride * buf->height / 2;
    202         uint8_t *dst_v = dst_y + dst_y_size;
    203         uint8_t *dst_u = dst_v + dst_c_size;
    204 
    205         for (int y = 0; y < mCropHeight; ++y) {
    206             memcpy(dst_y, src_y, mCropWidth);
    207 
    208             src_y += mWidth;
    209             dst_y += buf->stride;
    210         }
    211 
    212         for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
    213             size_t tmp = (mCropWidth + 1) / 2;
    214             for (size_t x = 0; x < tmp; ++x) {
    215                 dst_u[x] = src_uv[2 * x];
    216                 dst_v[x] = src_uv[2 * x + 1];
    217             }
    218 
    219             src_uv += mWidth;
    220             dst_u += dst_c_stride;
    221             dst_v += dst_c_stride;
    222         }
    223     }
    224 
    225     CHECK_EQ(0, mapper.unlock(buf->handle));
    226 
    227     if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf)) != 0) {
    228         LOGW("Surface::queueBuffer returned error %d", err);
    229     }
    230     buf = NULL;
    231 }
    232 
    233 }  // namespace android
    234