blob: 7b928709be14e9c131de1a75d37cfdc8277eb1ef [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* 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 */