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/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(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 
     56 SoftwareRenderer::~SoftwareRenderer() {
     57     delete mConverter;
     58     mConverter = NULL;
     59 }
     60 
     61 void 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     int halFormat;
    102     size_t bufWidth, bufHeight;
    103 
    104     switch (mColorFormat) {
    105         case OMX_COLOR_FormatYUV420Planar:
    106         case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
    107         {
    108             if (!runningInEmulator()) {
    109                 halFormat = HAL_PIXEL_FORMAT_YV12;
    110                 bufWidth = (mCropWidth + 1) & ~1;
    111                 bufHeight = (mCropHeight + 1) & ~1;
    112                 break;
    113             }
    114 
    115             // fall through.
    116         }
    117 
    118         default:
    119             halFormat = HAL_PIXEL_FORMAT_RGB_565;
    120             bufWidth = mCropWidth;
    121             bufHeight = mCropHeight;
    122 
    123             mConverter = new ColorConverter(
    124                     mColorFormat, OMX_COLOR_Format16bitRGB565);
    125             CHECK(mConverter->isValid());
    126             break;
    127     }
    128 
    129     CHECK(mNativeWindow != NULL);
    130     CHECK(mCropWidth > 0);
    131     CHECK(mCropHeight > 0);
    132     CHECK(mConverter == NULL || mConverter->isValid());
    133 
    134     CHECK_EQ(0,
    135             native_window_set_usage(
    136             mNativeWindow.get(),
    137             GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
    138             | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
    139 
    140     CHECK_EQ(0,
    141             native_window_set_scaling_mode(
    142             mNativeWindow.get(),
    143             NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
    144 
    145     // Width must be multiple of 32???
    146     CHECK_EQ(0, native_window_set_buffers_dimensions(
    147                 mNativeWindow.get(),
    148                 bufWidth,
    149                 bufHeight));
    150     CHECK_EQ(0, native_window_set_buffers_format(
    151                 mNativeWindow.get(),
    152                 halFormat));
    153 
    154     // NOTE: native window uses extended right-bottom coordinate
    155     android_native_rect_t crop;
    156     crop.left = mCropLeft;
    157     crop.top = mCropTop;
    158     crop.right = mCropRight + 1;
    159     crop.bottom = mCropBottom + 1;
    160     ALOGV("setting crop: [%d, %d, %d, %d] for size [%zu, %zu]",
    161           crop.left, crop.top, crop.right, crop.bottom, bufWidth, bufHeight);
    162 
    163     CHECK_EQ(0, native_window_set_crop(mNativeWindow.get(), &crop));
    164 
    165     int32_t rotationDegrees;
    166     if (!format->findInt32("rotation-degrees", &rotationDegrees)) {
    167         rotationDegrees = 0;
    168     }
    169     uint32_t transform;
    170     switch (rotationDegrees) {
    171         case 0: transform = 0; break;
    172         case 90: transform = HAL_TRANSFORM_ROT_90; break;
    173         case 180: transform = HAL_TRANSFORM_ROT_180; break;
    174         case 270: transform = HAL_TRANSFORM_ROT_270; break;
    175         default: transform = 0; break;
    176     }
    177 
    178     CHECK_EQ(0, native_window_set_buffers_transform(
    179                 mNativeWindow.get(), transform));
    180 }
    181 
    182 void SoftwareRenderer::render(
    183         const void *data, size_t /*size*/, int64_t timestampNs,
    184         void* /*platformPrivate*/, const sp<AMessage>& format) {
    185     resetFormatIfChanged(format);
    186 
    187     ANativeWindowBuffer *buf;
    188     int err;
    189     if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(),
    190             &buf)) != 0) {
    191         ALOGW("Surface::dequeueBuffer returned error %d", err);
    192         return;
    193     }
    194 
    195     GraphicBufferMapper &mapper = GraphicBufferMapper::get();
    196 
    197     Rect bounds(mCropWidth, mCropHeight);
    198 
    199     void *dst;
    200     CHECK_EQ(0, mapper.lock(
    201                 buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
    202 
    203     if (mConverter) {
    204         mConverter->convert(
    205                 data,
    206                 mWidth, mHeight,
    207                 mCropLeft, mCropTop, mCropRight, mCropBottom,
    208                 dst,
    209                 buf->stride, buf->height,
    210                 0, 0, mCropWidth - 1, mCropHeight - 1);
    211     } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
    212         const uint8_t *src_y = (const uint8_t *)data;
    213         const uint8_t *src_u = (const uint8_t *)data + mWidth * mHeight;
    214         const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
    215 
    216         uint8_t *dst_y = (uint8_t *)dst;
    217         size_t dst_y_size = buf->stride * buf->height;
    218         size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
    219         size_t dst_c_size = dst_c_stride * buf->height / 2;
    220         uint8_t *dst_v = dst_y + dst_y_size;
    221         uint8_t *dst_u = dst_v + dst_c_size;
    222 
    223         for (int y = 0; y < mCropHeight; ++y) {
    224             memcpy(dst_y, src_y, mCropWidth);
    225 
    226             src_y += mWidth;
    227             dst_y += buf->stride;
    228         }
    229 
    230         for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
    231             memcpy(dst_u, src_u, (mCropWidth + 1) / 2);
    232             memcpy(dst_v, src_v, (mCropWidth + 1) / 2);
    233 
    234             src_u += mWidth / 2;
    235             src_v += mWidth / 2;
    236             dst_u += dst_c_stride;
    237             dst_v += dst_c_stride;
    238         }
    239     } else {
    240         CHECK_EQ(mColorFormat, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar);
    241 
    242         const uint8_t *src_y =
    243             (const uint8_t *)data;
    244 
    245         const uint8_t *src_uv =
    246             (const uint8_t *)data + mWidth * (mHeight - mCropTop / 2);
    247 
    248         uint8_t *dst_y = (uint8_t *)dst;
    249 
    250         size_t dst_y_size = buf->stride * buf->height;
    251         size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
    252         size_t dst_c_size = dst_c_stride * buf->height / 2;
    253         uint8_t *dst_v = dst_y + dst_y_size;
    254         uint8_t *dst_u = dst_v + dst_c_size;
    255 
    256         for (int y = 0; y < mCropHeight; ++y) {
    257             memcpy(dst_y, src_y, mCropWidth);
    258 
    259             src_y += mWidth;
    260             dst_y += buf->stride;
    261         }
    262 
    263         for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
    264             size_t tmp = (mCropWidth + 1) / 2;
    265             for (size_t x = 0; x < tmp; ++x) {
    266                 dst_u[x] = src_uv[2 * x];
    267                 dst_v[x] = src_uv[2 * x + 1];
    268             }
    269 
    270             src_uv += mWidth;
    271             dst_u += dst_c_stride;
    272             dst_v += dst_c_stride;
    273         }
    274     }
    275 
    276     CHECK_EQ(0, mapper.unlock(buf->handle));
    277 
    278     if ((err = native_window_set_buffers_timestamp(mNativeWindow.get(),
    279             timestampNs)) != 0) {
    280         ALOGW("Surface::set_buffers_timestamp returned error %d", err);
    281     }
    282 
    283     if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf,
    284             -1)) != 0) {
    285         ALOGW("Surface::queueBuffer returned error %d", err);
    286     }
    287     buf = NULL;
    288 }
    289 
    290 }  // namespace android
    291