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