Home | History | Annotate | Download | only in libstagefrighthw
      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 "TIHardwareRenderer"
     18 #include <utils/Log.h>
     19 
     20 #include "TIHardwareRenderer.h"
     21 
     22 #include <media/stagefright/MediaDebug.h>
     23 #include <surfaceflinger/ISurface.h>
     24 #include <ui/Overlay.h>
     25 
     26 #include "v4l2_utils.h"
     27 
     28 #define CACHEABLE_BUFFERS 0x1
     29 
     30 namespace android {
     31 
     32 ////////////////////////////////////////////////////////////////////////////////
     33 
     34 TIHardwareRenderer::TIHardwareRenderer(
     35         const sp<ISurface> &surface,
     36         size_t displayWidth, size_t displayHeight,
     37         size_t decodedWidth, size_t decodedHeight,
     38         OMX_COLOR_FORMATTYPE colorFormat)
     39     : mISurface(surface),
     40       mDisplayWidth(displayWidth),
     41       mDisplayHeight(displayHeight),
     42       mDecodedWidth(decodedWidth),
     43       mDecodedHeight(decodedHeight),
     44       mColorFormat(colorFormat),
     45       mInitCheck(NO_INIT),
     46       mFrameSize(mDecodedWidth * mDecodedHeight * 2),
     47       mIsFirstFrame(true),
     48       mIndex(0) {
     49     CHECK(mISurface.get() != NULL);
     50     CHECK(mDecodedWidth > 0);
     51     CHECK(mDecodedHeight > 0);
     52 
     53     if (colorFormat != OMX_COLOR_FormatCbYCrY
     54             && colorFormat != OMX_COLOR_FormatYUV420Planar) {
     55         return;
     56     }
     57 
     58     sp<OverlayRef> ref = mISurface->createOverlay(
     59             mDecodedWidth, mDecodedHeight, OVERLAY_FORMAT_CbYCrY_422_I, 0);
     60 
     61     if (ref.get() == NULL) {
     62         LOGE("Unable to create the overlay!");
     63         return;
     64     }
     65 
     66     mOverlay = new Overlay(ref);
     67     mOverlay->setParameter(CACHEABLE_BUFFERS, 0);
     68 
     69     for (size_t i = 0; i < (size_t)mOverlay->getBufferCount(); ++i) {
     70         mapping_data_t *data =
     71             (mapping_data_t *)mOverlay->getBufferAddress((void *)i);
     72 
     73         mOverlayAddresses.push(data->ptr);
     74     }
     75 
     76     mInitCheck = OK;
     77 }
     78 
     79 TIHardwareRenderer::~TIHardwareRenderer() {
     80     if (mOverlay.get() != NULL) {
     81         mOverlay->destroy();
     82         mOverlay.clear();
     83 
     84         // XXX apparently destroying an overlay is an asynchronous process...
     85         sleep(1);
     86     }
     87 }
     88 
     89 // return a byte offset from any pointer
     90 static inline const void *byteOffset(const void* p, size_t offset) {
     91     return ((uint8_t*)p + offset);
     92 }
     93 
     94 static void convertYuv420ToYuv422(
     95         int width, int height, const void *src, void *dst) {
     96     // calculate total number of pixels, and offsets to U and V planes
     97     int pixelCount = height * width;
     98     int srcLineLength = width / 4;
     99     int destLineLength = width / 2;
    100     uint32_t* ySrc = (uint32_t*) src;
    101     const uint16_t* uSrc = (const uint16_t*) byteOffset(src, pixelCount);
    102     const uint16_t* vSrc = (const uint16_t*) byteOffset(uSrc, pixelCount >> 2);
    103     uint32_t *p = (uint32_t*) dst;
    104 
    105     // convert lines
    106     for (int i = 0; i < height; i += 2) {
    107 
    108         // upsample by repeating the UV values on adjacent lines
    109         // to save memory accesses, we handle 2 adjacent lines at a time
    110         // convert 4 pixels in 2 adjacent lines at a time
    111         for (int j = 0; j < srcLineLength; j++) {
    112 
    113             // fetch 4 Y values for each line
    114             uint32_t y0 = ySrc[0];
    115             uint32_t y1 = ySrc[srcLineLength];
    116             ySrc++;
    117 
    118             // fetch 2 U/V values
    119             uint32_t u = *uSrc++;
    120             uint32_t v = *vSrc++;
    121 
    122             // assemble first U/V pair, leave holes for Y's
    123             uint32_t uv = (u | (v << 16)) & 0x00ff00ff;
    124 
    125             // OR y values and write to memory
    126             p[0] = ((y0 & 0xff) << 8) | ((y0 & 0xff00) << 16) | uv;
    127             p[destLineLength] = ((y1 & 0xff) << 8) | ((y1 & 0xff00) << 16) | uv;
    128             p++;
    129 
    130             // assemble second U/V pair, leave holes for Y's
    131             uv = ((u >> 8) | (v << 8)) & 0x00ff00ff;
    132 
    133             // OR y values and write to memory
    134             p[0] = ((y0 >> 8) & 0xff00) | (y0 & 0xff000000) | uv;
    135             p[destLineLength] = ((y1 >> 8) & 0xff00) | (y1 & 0xff000000) | uv;
    136             p++;
    137         }
    138 
    139         // skip the next y line, we already converted it
    140         ySrc += srcLineLength;
    141         p += destLineLength;
    142     }
    143 }
    144 
    145 void TIHardwareRenderer::render(
    146         const void *data, size_t size, void *platformPrivate) {
    147     // CHECK_EQ(size, mFrameSize);
    148 
    149     if (mOverlay.get() == NULL) {
    150         return;
    151     }
    152 
    153 #if 0
    154     size_t i = 0;
    155     for (; i < mOverlayAddresses.size(); ++i) {
    156         if (mOverlayAddresses[i] == data) {
    157             break;
    158         }
    159 
    160         if (mIsFirstFrame) {
    161             LOGI("overlay buffer #%d: %p", i, mOverlayAddresses[i]);
    162         }
    163     }
    164 
    165     if (i == mOverlayAddresses.size()) {
    166         LOGE("No suitable overlay buffer found.");
    167         return;
    168     }
    169 
    170     mOverlay->queueBuffer((void *)i);
    171 
    172     overlay_buffer_t overlay_buffer;
    173     if (!mIsFirstFrame) {
    174         CHECK_EQ(mOverlay->dequeueBuffer(&overlay_buffer), OK);
    175     } else {
    176         mIsFirstFrame = false;
    177     }
    178 #else
    179     if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
    180         convertYuv420ToYuv422(
    181                 mDecodedWidth, mDecodedHeight, data, mOverlayAddresses[mIndex]);
    182     } else {
    183         CHECK_EQ(mColorFormat, OMX_COLOR_FormatCbYCrY);
    184 
    185         memcpy(mOverlayAddresses[mIndex], data, size);
    186     }
    187 
    188     if (mOverlay->queueBuffer((void *)mIndex) == ALL_BUFFERS_FLUSHED) {
    189         mIsFirstFrame = true;
    190         if (mOverlay->queueBuffer((void *)mIndex) != 0) {
    191             return;
    192         }
    193     }
    194 
    195     if (++mIndex == mOverlayAddresses.size()) {
    196         mIndex = 0;
    197     }
    198 
    199     overlay_buffer_t overlay_buffer;
    200     if (!mIsFirstFrame) {
    201         status_t err = mOverlay->dequeueBuffer(&overlay_buffer);
    202 
    203         if (err == ALL_BUFFERS_FLUSHED) {
    204             mIsFirstFrame = true;
    205         } else {
    206             return;
    207         }
    208     } else {
    209         mIsFirstFrame = false;
    210     }
    211 #endif
    212 }
    213 
    214 }  // namespace android
    215 
    216