SoftVideoEncoderOMXComponent.cpp revision 2edda09a2ad1d112c52acd37d323f63f0a492d67
1/* 2 * Copyright 2014 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#include <inttypes.h> 18 19//#define LOG_NDEBUG 0 20#define LOG_TAG "SoftVideoEncoderOMXComponent" 21#include <utils/Log.h> 22 23#include "include/SoftVideoEncoderOMXComponent.h" 24 25#include <hardware/gralloc.h> 26#include <media/hardware/HardwareAPI.h> 27#include <media/stagefright/foundation/ADebug.h> 28#include <media/stagefright/foundation/ALooper.h> 29#include <media/stagefright/foundation/AMessage.h> 30#include <media/stagefright/MediaDefs.h> 31 32#include <ui/GraphicBuffer.h> 33#include <ui/GraphicBufferMapper.h> 34 35namespace android { 36 37SoftVideoEncoderOMXComponent::SoftVideoEncoderOMXComponent( 38 const char *name, 39 const OMX_CALLBACKTYPE *callbacks, 40 OMX_PTR appData, 41 OMX_COMPONENTTYPE **component) 42 : SimpleSoftOMXComponent(name, callbacks, appData, component), 43 mGrallocModule(NULL) { 44} 45 46// static 47void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar( 48 uint8_t *dst, size_t dstStride, size_t dstVStride, 49 struct android_ycbcr *ycbcr, int32_t width, int32_t height) { 50 const uint8_t *src = (const uint8_t *)ycbcr->y; 51 const uint8_t *srcU = (const uint8_t *)ycbcr->cb; 52 const uint8_t *srcV = (const uint8_t *)ycbcr->cr; 53 uint8_t *dstU = dst + dstVStride * dstStride; 54 uint8_t *dstV = dstU + (dstVStride >> 1) * (dstStride >> 1); 55 56 for (size_t y = height; y > 0; --y) { 57 memcpy(dst, src, width); 58 dst += dstStride; 59 src += ycbcr->ystride; 60 } 61 if (ycbcr->cstride == ycbcr->ystride >> 1 && ycbcr->chroma_step == 1) { 62 // planar 63 for (size_t y = height >> 1; y > 0; --y) { 64 memcpy(dstU, srcU, width >> 1); 65 dstU += dstStride >> 1; 66 srcU += ycbcr->cstride; 67 memcpy(dstV, srcV, width >> 1); 68 dstV += dstStride >> 1; 69 srcV += ycbcr->cstride; 70 } 71 } else { 72 // arbitrary 73 for (size_t y = height >> 1; y > 0; --y) { 74 for (size_t x = width >> 1; x > 0; --x) { 75 *dstU++ = *srcU; 76 *dstV++ = *srcV; 77 srcU += ycbcr->chroma_step; 78 srcV += ycbcr->chroma_step; 79 } 80 dstU += (dstStride >> 1) - (width >> 1); 81 dstV += (dstStride >> 1) - (width >> 1); 82 srcU += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step; 83 srcV += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step; 84 } 85 } 86} 87 88// static 89void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar( 90 const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) { 91 // TODO: add support for stride 92 int32_t outYsize = width * height; 93 uint32_t *outY = (uint32_t *) outYUV; 94 uint16_t *outCb = (uint16_t *) (outYUV + outYsize); 95 uint16_t *outCr = (uint16_t *) (outYUV + outYsize + (outYsize >> 2)); 96 97 /* Y copying */ 98 memcpy(outY, inYVU, outYsize); 99 100 /* U & V copying */ 101 // FIXME this only works if width is multiple of 4 102 uint32_t *inYVU_4 = (uint32_t *) (inYVU + outYsize); 103 for (int32_t i = height >> 1; i > 0; --i) { 104 for (int32_t j = width >> 2; j > 0; --j) { 105 uint32_t temp = *inYVU_4++; 106 uint32_t tempU = temp & 0xFF; 107 tempU = tempU | ((temp >> 8) & 0xFF00); 108 109 uint32_t tempV = (temp >> 8) & 0xFF; 110 tempV = tempV | ((temp >> 16) & 0xFF00); 111 112 *outCb++ = tempU; 113 *outCr++ = tempV; 114 } 115 } 116} 117 118// static 119void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar( 120 uint8_t *dstY, size_t dstStride, size_t dstVStride, 121 const uint8_t *src, size_t width, size_t height, size_t srcStride, 122 bool bgr) { 123 CHECK((width & 1) == 0); 124 CHECK((height & 1) == 0); 125 126 uint8_t *dstU = dstY + dstStride * dstVStride; 127 uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1); 128 129#ifdef SURFACE_IS_BGR32 130 bgr = !bgr; 131#endif 132 133 const size_t redOffset = bgr ? 2 : 0; 134 const size_t greenOffset = 1; 135 const size_t blueOffset = bgr ? 0 : 2; 136 137 for (size_t y = 0; y < height; ++y) { 138 for (size_t x = 0; x < width; ++x) { 139 unsigned red = src[redOffset]; 140 unsigned green = src[greenOffset]; 141 unsigned blue = src[blueOffset]; 142 143 // using ITU-R BT.601 conversion matrix 144 unsigned luma = 145 ((red * 66 + green * 129 + blue * 25) >> 8) + 16; 146 147 dstY[x] = luma; 148 149 if ((x & 1) == 0 && (y & 1) == 0) { 150 unsigned U = 151 ((-red * 38 - green * 74 + blue * 112) >> 8) + 128; 152 153 unsigned V = 154 ((red * 112 - green * 94 - blue * 18) >> 8) + 128; 155 156 dstU[x >> 1] = U; 157 dstV[x >> 1] = V; 158 } 159 src += 4; 160 } 161 162 if ((y & 1) == 0) { 163 dstU += dstStride >> 1; 164 dstV += dstStride >> 1; 165 } 166 167 src += srcStride - 4 * width; 168 dstY += dstStride; 169 } 170} 171 172const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer( 173 uint8_t *dst, size_t dstSize, 174 const uint8_t *src, size_t srcSize, 175 size_t width, size_t height) const { 176 size_t dstStride = width; 177 size_t dstVStride = height; 178 179 MetadataBufferType bufferType = *(MetadataBufferType *)src; 180 bool usingGraphicBuffer = bufferType == kMetadataBufferTypeGraphicBuffer; 181 if (!usingGraphicBuffer && bufferType != kMetadataBufferTypeGrallocSource) { 182 ALOGE("Unsupported metadata type (%d)", bufferType); 183 return NULL; 184 } 185 186 if (mGrallocModule == NULL) { 187 CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule)); 188 } 189 190 const gralloc_module_t *grmodule = 191 (const gralloc_module_t *)mGrallocModule; 192 193 buffer_handle_t handle; 194 int format; 195 size_t srcStride; 196 size_t srcVStride; 197 if (usingGraphicBuffer) { 198 if (srcSize < 4 + sizeof(GraphicBuffer *)) { 199 ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(GraphicBuffer *)); 200 return NULL; 201 } 202 203 GraphicBuffer *buffer = *(GraphicBuffer **)(src + 4); 204 handle = buffer->handle; 205 format = buffer->format; 206 srcStride = buffer->stride; 207 srcVStride = buffer->height; 208 // convert stride from pixels to bytes 209 if (format != HAL_PIXEL_FORMAT_YV12 && 210 format != HAL_PIXEL_FORMAT_YCbCr_420_888) { 211 // TODO do we need to support other formats? 212 srcStride *= 4; 213 } 214 } else { 215 // TODO: remove this part. Check if anyone uses this. 216 217 if (srcSize < 4 + sizeof(buffer_handle_t)) { 218 ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(buffer_handle_t)); 219 return NULL; 220 } 221 222 handle = *(buffer_handle_t *)(src + 4); 223 // assume HAL_PIXEL_FORMAT_RGBA_8888 224 // there is no way to get the src stride without the graphic buffer 225 format = HAL_PIXEL_FORMAT_RGBA_8888; 226 srcStride = width * 4; 227 srcVStride = height; 228 } 229 230 size_t neededSize = 231 dstStride * dstVStride + (width >> 1) 232 + (dstStride >> 1) * ((dstVStride >> 1) + (height >> 1) - 1); 233 if (dstSize < neededSize) { 234 ALOGE("destination buffer is too small (%zu vs %zu)", dstSize, neededSize); 235 return NULL; 236 } 237 238 void *bits = NULL; 239 struct android_ycbcr ycbcr; 240 status_t res; 241 if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { 242 res = grmodule->lock_ycbcr( 243 grmodule, handle, 244 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, 245 0, 0, width, height, &ycbcr); 246 } else { 247 res = grmodule->lock( 248 grmodule, handle, 249 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, 250 0, 0, width, height, &bits); 251 } 252 if (res != OK) { 253 ALOGE("Unable to lock image buffer %p for access", handle); 254 return NULL; 255 } 256 257 switch (format) { 258 case HAL_PIXEL_FORMAT_YV12: // YCrCb / YVU planar 259 // convert to flex YUV 260 ycbcr.y = bits; 261 ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride; 262 ycbcr.cb = (uint8_t *)ycbcr.cr + (srcStride >> 1) * (srcVStride >> 1); 263 ycbcr.chroma_step = 1; 264 ycbcr.cstride = srcVStride >> 1; 265 ycbcr.ystride = srcVStride; 266 ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); 267 break; 268 case HAL_PIXEL_FORMAT_YCrCb_420_SP: // YCrCb / YVU semiplanar, NV21 269 // convert to flex YUV 270 ycbcr.y = bits; 271 ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride; 272 ycbcr.cb = (uint8_t *)ycbcr.cr + 1; 273 ycbcr.chroma_step = 2; 274 ycbcr.cstride = srcVStride; 275 ycbcr.ystride = srcVStride; 276 ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); 277 break; 278 case HAL_PIXEL_FORMAT_YCbCr_420_888: 279 ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); 280 break; 281 case HAL_PIXEL_FORMAT_RGBA_8888: 282 case HAL_PIXEL_FORMAT_BGRA_8888: 283 ConvertRGB32ToPlanar( 284 dst, dstStride, dstVStride, 285 (const uint8_t *)bits, width, height, srcStride, 286 format == HAL_PIXEL_FORMAT_BGRA_8888); 287 break; 288 default: 289 ALOGE("Unsupported pixel format %#x", format); 290 dst = NULL; 291 break; 292 } 293 294 if (grmodule->unlock(grmodule, handle) != OK) { 295 ALOGE("Unable to unlock image buffer %p for access", handle); 296 } 297 298 return dst; 299} 300 301OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex( 302 const char *name, OMX_INDEXTYPE *index) { 303 if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") || 304 !strcmp(name, "OMX.google.android.index.storeGraphicBufferInMetaData")) { 305 *(int32_t*)index = kStoreMetaDataExtensionIndex; 306 return OMX_ErrorNone; 307 } 308 return SimpleSoftOMXComponent::getExtensionIndex(name, index); 309} 310 311} // namespace android 312