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