/* * Copyright (C) 2009 The Android Open Source Project * Modified for use by h264bsd standalone library * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*------------------------------------------------------------------------------ Table of contents 1. Include headers 2. External compiler flags 3. Module defines 4. Local function prototypes 5. Functions h264bsdWriteMacroblock h264bsdWriteOutputBlocks ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ 1. Include headers ------------------------------------------------------------------------------*/ #include "h264bsd_image.h" #include "h264bsd_util.h" #include "h264bsd_neighbour.h" /*------------------------------------------------------------------------------ 2. External compiler flags -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- 3. Module defines ------------------------------------------------------------------------------*/ /* x- and y-coordinates for each block, defined in h264bsd_intra_prediction.c */ extern const u32 h264bsdBlockX[]; extern const u32 h264bsdBlockY[]; /* clipping table, defined in h264bsd_intra_prediction.c */ extern const u8 h264bsdClip[]; /*------------------------------------------------------------------------------ 4. Local function prototypes ------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------ Function: h264bsdWriteMacroblock Functional description: Write one macroblock into the image. Both luma and chroma components will be written at the same time. Inputs: data pointer to macroblock data to be written, 256 values for luma followed by 64 values for both chroma components Outputs: image pointer to the image where the macroblock will be written Returns: none ------------------------------------------------------------------------------*/ #ifndef H264DEC_NEON void h264bsdWriteMacroblock(image_t *image, u8 *data) { /* Variables */ u32 i; u32 width; u32 *lum, *cb, *cr; u32 *ptr; u32 tmp1, tmp2; /* Code */ ASSERT(image); ASSERT(data); ASSERT(!((u32)data&0x3)); width = image->width; /*lint -save -e826 lum, cb and cr used to copy 4 bytes at the time, disable * "area too small" info message */ lum = (u32*)image->luma; cb = (u32*)image->cb; cr = (u32*)image->cr; ASSERT(!((u32)lum&0x3)); ASSERT(!((u32)cb&0x3)); ASSERT(!((u32)cr&0x3)); ptr = (u32*)data; width *= 4; for (i = 16; i ; i--) { tmp1 = *ptr++; tmp2 = *ptr++; *lum++ = tmp1; *lum++ = tmp2; tmp1 = *ptr++; tmp2 = *ptr++; *lum++ = tmp1; *lum++ = tmp2; lum += width-4; } width >>= 1; for (i = 8; i ; i--) { tmp1 = *ptr++; tmp2 = *ptr++; *cb++ = tmp1; *cb++ = tmp2; cb += width-2; } for (i = 8; i ; i--) { tmp1 = *ptr++; tmp2 = *ptr++; *cr++ = tmp1; *cr++ = tmp2; cr += width-2; } } #endif #ifndef H264DEC_OMXDL /*------------------------------------------------------------------------------ Function: h264bsdWriteOutputBlocks Functional description: Write one macroblock into the image. Prediction for the macroblock and the residual are given separately and will be combined while writing the data to the image Inputs: data pointer to macroblock prediction data, 256 values for luma followed by 64 values for both chroma components mbNum number of the macroblock residual pointer to residual data, 16 16-element arrays for luma followed by 4 16-element arrays for both chroma components Outputs: image pointer to the image where the data will be written Returns: none ------------------------------------------------------------------------------*/ void h264bsdWriteOutputBlocks(image_t *image, u32 mbNum, u8 *data, i32 residual[][16]) { /* Variables */ u32 i; u32 picWidth, picSize; u8 *lum, *cb, *cr; u8 *imageBlock; u8 *tmp; u32 row, col; u32 block; u32 x, y; i32 *pRes; i32 tmp1, tmp2, tmp3, tmp4; const u8 *clp = h264bsdClip + 512; /* Code */ ASSERT(image); ASSERT(data); ASSERT(mbNum < image->width * image->height); ASSERT(!((u32)data&0x3)); /* Image size in macroblocks */ picWidth = image->width; picSize = picWidth * image->height; row = mbNum / picWidth; col = mbNum % picWidth; /* Output macroblock position in output picture */ lum = (image->data + row * picWidth * 256 + col * 16); cb = (image->data + picSize * 256 + row * picWidth * 64 + col * 8); cr = (cb + picSize * 64); picWidth *= 16; for (block = 0; block < 16; block++) { x = h264bsdBlockX[block]; y = h264bsdBlockY[block]; pRes = residual[block]; ASSERT(pRes); tmp = data + y*16 + x; imageBlock = lum + y*picWidth + x; ASSERT(!((u32)tmp&0x3)); ASSERT(!((u32)imageBlock&0x3)); if (IS_RESIDUAL_EMPTY(pRes)) { /*lint -e826 */ i32 *in32 = (i32*)tmp; i32 *out32 = (i32*)imageBlock; /* Residual is zero => copy prediction block to output */ tmp1 = *in32; in32 += 4; tmp2 = *in32; in32 += 4; *out32 = tmp1; out32 += picWidth/4; *out32 = tmp2; out32 += picWidth/4; tmp1 = *in32; in32 += 4; tmp2 = *in32; *out32 = tmp1; out32 += picWidth/4; *out32 = tmp2; } else { RANGE_CHECK_ARRAY(pRes, -512, 511, 16); /* Calculate image = prediction + residual * Process four pixels in a loop */ for (i = 4; i; i--) { tmp1 = tmp[0]; tmp2 = *pRes++; tmp3 = tmp[1]; tmp1 = clp[tmp1 + tmp2]; tmp4 = *pRes++; imageBlock[0] = (u8)tmp1; tmp3 = clp[tmp3 + tmp4]; tmp1 = tmp[2]; tmp2 = *pRes++; imageBlock[1] = (u8)tmp3; tmp1 = clp[tmp1 + tmp2]; tmp3 = tmp[3]; tmp4 = *pRes++; imageBlock[2] = (u8)tmp1; tmp3 = clp[tmp3 + tmp4]; tmp += 16; imageBlock[3] = (u8)tmp3; imageBlock += picWidth; } } } picWidth /= 2; for (block = 16; block <= 23; block++) { x = h264bsdBlockX[block & 0x3]; y = h264bsdBlockY[block & 0x3]; pRes = residual[block]; ASSERT(pRes); tmp = data + 256; imageBlock = cb; if (block >= 20) { imageBlock = cr; tmp += 64; } tmp += y*8 + x; imageBlock += y*picWidth + x; ASSERT(!((u32)tmp&0x3)); ASSERT(!((u32)imageBlock&0x3)); if (IS_RESIDUAL_EMPTY(pRes)) { /*lint -e826 */ i32 *in32 = (i32*)tmp; i32 *out32 = (i32*)imageBlock; /* Residual is zero => copy prediction block to output */ tmp1 = *in32; in32 += 2; tmp2 = *in32; in32 += 2; *out32 = tmp1; out32 += picWidth/4; *out32 = tmp2; out32 += picWidth/4; tmp1 = *in32; in32 += 2; tmp2 = *in32; *out32 = tmp1; out32 += picWidth/4; *out32 = tmp2; } else { RANGE_CHECK_ARRAY(pRes, -512, 511, 16); for (i = 4; i; i--) { tmp1 = tmp[0]; tmp2 = *pRes++; tmp3 = tmp[1]; tmp1 = clp[tmp1 + tmp2]; tmp4 = *pRes++; imageBlock[0] = (u8)tmp1; tmp3 = clp[tmp3 + tmp4]; tmp1 = tmp[2]; tmp2 = *pRes++; imageBlock[1] = (u8)tmp3; tmp1 = clp[tmp1 + tmp2]; tmp3 = tmp[3]; tmp4 = *pRes++; imageBlock[2] = (u8)tmp1; tmp3 = clp[tmp3 + tmp4]; tmp += 8; imageBlock[3] = (u8)tmp3; imageBlock += picWidth; } } } } #endif /* H264DEC_OMXDL */