blob: 6a5e0b63ce6ef72ecc024655b9c5b2cfc4d57c6d [file] [log] [blame]
/*
* Copyright (C) 2011 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.
*/
/**
******************************************************************************
* @file M4TRAN_transition.c
* @brief
******************************************************************************
*/
/**
* OSAL (memset and memcpy) ***/
#include "M4OSA_Memory.h"
#include "M4VFL_transition.h"
#include <string.h>
#ifdef LITTLE_ENDIAN
#define M4VFL_SWAP_SHORT(a) a = ((a & 0xFF) << 8) | ((a & 0xFF00) >> 8)
#else
#define M4VFL_SWAP_SHORT(a)
#endif
#define LUM_FACTOR_MAX 10
unsigned char M4VFL_modifyLumaByStep(M4ViComImagePlane *plane_in, M4ViComImagePlane *plane_out,
M4VFL_ModifLumParam *lum_param, void *user_data)
{
unsigned short *p_src, *p_dest, *p_src_line, *p_dest_line;
unsigned long pix_src;
unsigned long u_outpx, u_outpx2;
unsigned long u_width, u_stride, u_stride_out,u_height, pix;
unsigned long lf1, lf2, lf3;
long i, j;
if (lum_param->copy_chroma != 0)
{
/* copy chroma plane */
}
/* apply luma factor */
u_width = plane_in[0].u_width;
u_height = plane_in[0].u_height;
u_stride = (plane_in[0].u_stride >> 1);
u_stride_out = (plane_out[0].u_stride >> 1);
p_dest = (unsigned short *) &plane_out[0].pac_data[plane_out[0].u_topleft];
p_src = (unsigned short *) &plane_in[0].pac_data[plane_in[0].u_topleft];
p_dest_line = p_dest;
p_src_line = p_src;
switch(lum_param->lum_factor)
{
case 0:
/* very specific case : set luma plane to 16 */
for (j = u_height; j != 0; j--)
{
memset((void *)p_dest,16, u_width);
p_dest += u_stride_out;
}
return 0;
case 1:
/* 0.25 */
lf1 = 6; lf2 = 6; lf3 = 7;
break;
case 2:
/* 0.375 */
lf1 = 7; lf2 = 7; lf3 = 7;
break;
case 3:
/* 0.5 */
lf1 = 7; lf2 = 7; lf3 = 8;
break;
case 4:
/* 0.625 */
lf1 = 7; lf2 = 8; lf3 = 8;
break;
case 5:
/* 0.75 */
lf1 = 8; lf2 = 8; lf3 = 8;
break;
case 6:
/* 0.875 */
lf1 = 9; lf2 = 8; lf3 = 7;
break;
default:
lf1 = 8; lf2 = 8; lf3 = 9;
break;
}
for (j = u_height; j != 0; j--)
{
p_dest = p_dest_line;
p_src = p_src_line;
for (i = (u_width >> 1); i != 0; i--)
{
pix_src = (unsigned long) *p_src++;
pix = pix_src & 0xFF;
u_outpx = (((pix << lf1) + (pix << lf2) + (pix << lf3) ) >> LUM_FACTOR_MAX);
pix = ((pix_src & 0xFF00) >> 8);
u_outpx2 = ((((pix << lf1) + (pix << lf2) + (pix << lf3) ) >> LUM_FACTOR_MAX)<< 8) ;
*p_dest++ = (unsigned short) (u_outpx2 | u_outpx);
}
p_dest_line += u_stride_out;
p_src_line += u_stride;
}
return 0;
}
unsigned char M4VFL_modifyLumaWithScale(M4ViComImagePlane *plane_in,
M4ViComImagePlane *plane_out,
unsigned long lum_factor,
void *user_data)
{
unsigned short *p_src, *p_dest, *p_src_line, *p_dest_line;
unsigned char *p_csrc, *p_cdest, *p_csrc_line, *p_cdest_line;
unsigned long pix_src;
unsigned long u_outpx, u_outpx2;
unsigned long u_width, u_stride, u_stride_out,u_height, pix;
long i, j;
/* copy or filter chroma */
u_width = plane_in[1].u_width;
u_height = plane_in[1].u_height;
u_stride = plane_in[1].u_stride;
u_stride_out = plane_out[1].u_stride;
p_cdest_line = (unsigned char *) &plane_out[1].pac_data[plane_out[1].u_topleft];
p_csrc_line = (unsigned char *) &plane_in[1].pac_data[plane_in[1].u_topleft];
if (lum_factor > 256)
{
p_cdest = (unsigned char *) &plane_out[2].pac_data[plane_out[2].u_topleft];
p_csrc = (unsigned char *) &plane_in[2].pac_data[plane_in[2].u_topleft];
/* copy chroma */
for (j = u_height; j != 0; j--)
{
for (i = u_width; i != 0; i--)
{
memcpy((void *)p_cdest_line, (void *)p_csrc_line, u_width);
memcpy((void *)p_cdest,(void *) p_csrc, u_width);
}
p_cdest_line += u_stride_out;
p_cdest += u_stride_out;
p_csrc_line += u_stride;
p_csrc += u_stride;
}
}
else
{
/* filter chroma */
pix = (1024 - lum_factor) << 7;
for (j = u_height; j != 0; j--)
{
p_cdest = p_cdest_line;
p_csrc = p_csrc_line;
for (i = u_width; i != 0; i--)
{
*p_cdest++ = ((pix + (*p_csrc++ & 0xFF) * lum_factor) >> LUM_FACTOR_MAX);
}
p_cdest_line += u_stride_out;
p_csrc_line += u_stride;
}
p_cdest_line = (unsigned char *) &plane_out[2].pac_data[plane_out[2].u_topleft];
p_csrc_line = (unsigned char *) &plane_in[2].pac_data[plane_in[2].u_topleft];
for (j = u_height; j != 0; j--)
{
p_cdest = p_cdest_line;
p_csrc = p_csrc_line;
for (i = u_width; i != 0; i--)
{
*p_cdest++ = ((pix + (*p_csrc & 0xFF) * lum_factor) >> LUM_FACTOR_MAX);
}
p_cdest_line += u_stride_out;
p_csrc_line += u_stride;
}
}
/* apply luma factor */
u_width = plane_in[0].u_width;
u_height = plane_in[0].u_height;
u_stride = (plane_in[0].u_stride >> 1);
u_stride_out = (plane_out[0].u_stride >> 1);
p_dest = (unsigned short *) &plane_out[0].pac_data[plane_out[0].u_topleft];
p_src = (unsigned short *) &plane_in[0].pac_data[plane_in[0].u_topleft];
p_dest_line = p_dest;
p_src_line = p_src;
for (j = u_height; j != 0; j--)
{
p_dest = p_dest_line;
p_src = p_src_line;
for (i = (u_width >> 1); i != 0; i--)
{
pix_src = (unsigned long) *p_src++;
pix = pix_src & 0xFF;
u_outpx = ((pix * lum_factor) >> LUM_FACTOR_MAX);
pix = ((pix_src & 0xFF00) >> 8);
u_outpx2 = (((pix * lum_factor) >> LUM_FACTOR_MAX)<< 8) ;
*p_dest++ = (unsigned short) (u_outpx2 | u_outpx);
}
p_dest_line += u_stride_out;
p_src_line += u_stride;
}
return 0;
}
/**
*************************************************************************************************
* M4OSA_ERR M4VIFI_ImageBlendingonYUV420 (void *pUserData,
* M4VIFI_ImagePlane *pPlaneIn1,
* M4VIFI_ImagePlane *pPlaneIn2,
* M4VIFI_ImagePlane *pPlaneOut,
* UInt32 Progress)
* @brief Blends two YUV 4:2:0 Planar images.
* @note Blends YUV420 planar images,
* Map the value of progress from (0 - 1000) to (0 - 1024)
* Set the range of blendingfactor,
* 1. from 0 to (Progress << 1) ;for Progress <= 512
* 2. from (( Progress - 512)<< 1) to 1024 ;otherwise
* Set the increment of blendingfactor for each element in the image row by the factor,
* = (Range-1) / (image width-1) ;for width >= range
* = (Range) / (image width) ;otherwise
* Loop on each(= i) row of output Y plane (steps of 2)
* Loop on each(= j) column of output Y plane (steps of 2)
* Get four Y samples and one U & V sample from two input YUV4:2:0 images and
* Compute four Y sample and one U & V sample for output YUV4:2:0 image
* using the following,
* Out(i,j) = blendingfactor(i,j) * In1(i,j)+ (l - blendingfactor(i,j)) *In2(i,j)
* end loop column
* end loop row.
* @param pUserData: (IN) User Specific Parameter
* @param pPlaneIn1: (IN) Pointer to an array of image plane structures maintained
* for Y, U and V planes.
* @param pPlaneIn2: (IN) Pointer to an array of image plane structures maintained
* for Y, U and V planes.
* @param pPlaneOut: (OUT) Pointer to an array of image plane structures maintained
* for Y, U and V planes.
* @param Progress: (IN) Progress value (varies between 0 and 1000)
* @return M4VIFI_OK: No error
* @return M4VIFI_ILLEGAL_FRAME_HEIGHT: Error in height
* @return M4VIFI_ILLEGAL_FRAME_WIDTH: Error in width
*************************************************************************************************
*/
/** Check for value is EVEN */
#ifndef IS_EVEN
#define IS_EVEN(a) (!(a & 0x01))
#endif
/** Used for fixed point implementation */
#ifndef MAX_SHORT
#define MAX_SHORT 0x10000
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef FALSE
#define FALSE 0
#define TRUE !FALSE
#endif
unsigned char M4VIFI_ImageBlendingonYUV420 (void *pUserData,
M4ViComImagePlane *pPlaneIn1,
M4ViComImagePlane *pPlaneIn2,
M4ViComImagePlane *pPlaneOut,
UInt32 Progress)
{
UInt8 *pu8_data_Y_start1,*pu8_data_U_start1,*pu8_data_V_start1;
UInt8 *pu8_data_Y_start2,*pu8_data_U_start2,*pu8_data_V_start2;
UInt8 *pu8_data_Y_start3,*pu8_data_U_start3,*pu8_data_V_start3;
UInt8 *pu8_data_Y_current1, *pu8_data_Y_next1, *pu8_data_U1, *pu8_data_V1;
UInt8 *pu8_data_Y_current2, *pu8_data_Y_next2, *pu8_data_U2, *pu8_data_V2;
UInt8 *pu8_data_Y_current3,*pu8_data_Y_next3, *pu8_data_U3, *pu8_data_V3;
UInt32 u32_stride_Y1, u32_stride2_Y1, u32_stride_U1, u32_stride_V1;
UInt32 u32_stride_Y2, u32_stride2_Y2, u32_stride_U2, u32_stride_V2;
UInt32 u32_stride_Y3, u32_stride2_Y3, u32_stride_U3, u32_stride_V3;
UInt32 u32_height, u32_width;
UInt32 u32_blendfactor, u32_startA, u32_endA, u32_blend_inc, u32_x_accum;
UInt32 u32_col, u32_row, u32_rangeA, u32_progress;
UInt32 u32_U1,u32_V1,u32_U2,u32_V2, u32_Y1, u32_Y2;
/* Check the Y plane height is EVEN and image plane heights are same */
if( (IS_EVEN(pPlaneIn1[0].u_height) == FALSE) ||
(IS_EVEN(pPlaneIn2[0].u_height) == FALSE) ||
(IS_EVEN(pPlaneOut[0].u_height) == FALSE) ||
(pPlaneIn1[0].u_height != pPlaneOut[0].u_height) ||
(pPlaneIn2[0].u_height != pPlaneOut[0].u_height) )
{
return M4VIFI_ILLEGAL_FRAME_HEIGHT;
}
/* Check the Y plane width is EVEN and image plane widths are same */
if( (IS_EVEN(pPlaneIn1[0].u_width) == FALSE) ||
(IS_EVEN(pPlaneIn2[0].u_width) == FALSE) ||
(IS_EVEN(pPlaneOut[0].u_width) == FALSE) ||
(pPlaneIn1[0].u_width != pPlaneOut[0].u_width) ||
(pPlaneIn2[0].u_width != pPlaneOut[0].u_width) )
{
return M4VIFI_ILLEGAL_FRAME_WIDTH;
}
/* Set the pointer to the beginning of the input1 YUV420 image planes */
pu8_data_Y_start1 = pPlaneIn1[0].pac_data + pPlaneIn1[0].u_topleft;
pu8_data_U_start1 = pPlaneIn1[1].pac_data + pPlaneIn1[1].u_topleft;
pu8_data_V_start1 = pPlaneIn1[2].pac_data + pPlaneIn1[2].u_topleft;
/* Set the pointer to the beginning of the input2 YUV420 image planes */
pu8_data_Y_start2 = pPlaneIn2[0].pac_data + pPlaneIn2[0].u_topleft;
pu8_data_U_start2 = pPlaneIn2[1].pac_data + pPlaneIn2[1].u_topleft;
pu8_data_V_start2 = pPlaneIn2[2].pac_data + pPlaneIn2[2].u_topleft;
/* Set the pointer to the beginning of the output YUV420 image planes */
pu8_data_Y_start3 = pPlaneOut[0].pac_data + pPlaneOut[0].u_topleft;
pu8_data_U_start3 = pPlaneOut[1].pac_data + pPlaneOut[1].u_topleft;
pu8_data_V_start3 = pPlaneOut[2].pac_data + pPlaneOut[2].u_topleft;
/* Set the stride for the next row in each input1 YUV420 plane */
u32_stride_Y1 = pPlaneIn1[0].u_stride;
u32_stride_U1 = pPlaneIn1[1].u_stride;
u32_stride_V1 = pPlaneIn1[2].u_stride;
/* Set the stride for the next row in each input2 YUV420 plane */
u32_stride_Y2 = pPlaneIn2[0].u_stride;
u32_stride_U2 = pPlaneIn2[1].u_stride;
u32_stride_V2 = pPlaneIn2[2].u_stride;
/* Set the stride for the next row in each output YUV420 plane */
u32_stride_Y3 = pPlaneOut[0].u_stride;
u32_stride_U3 = pPlaneOut[1].u_stride;
u32_stride_V3 = pPlaneOut[2].u_stride;
u32_stride2_Y1 = u32_stride_Y1 << 1;
u32_stride2_Y2 = u32_stride_Y2 << 1;
u32_stride2_Y3 = u32_stride_Y3 << 1;
/* Get the size of the output image */
u32_height = pPlaneOut[0].u_height;
u32_width = pPlaneOut[0].u_width;
/* User Specified Progress value */
u32_progress = Progress;
/* Map Progress value from (0 - 1000) to (0 - 1024) -> for optimisation */
if(u32_progress < 1000)
u32_progress = ((u32_progress << 10) / 1000);
else
u32_progress = 1024;
/* Set the range of blendingfactor */
if(u32_progress <= 512)
{
u32_startA = 0;
u32_endA = (u32_progress << 1);
}
else /* u32_progress > 512 */
{
u32_startA = (u32_progress - 512) << 1;
u32_endA = 1024;
}
u32_rangeA = u32_endA - u32_startA;
/* Set the increment of blendingfactor for each element in the image row */
if ((u32_width >= u32_rangeA) && (u32_rangeA > 0) )
{
u32_blend_inc = ((u32_rangeA-1) * MAX_SHORT) / (u32_width - 1);
}
else /* (u32_width < u32_rangeA) || (u32_rangeA < 0) */
{
u32_blend_inc = (u32_rangeA * MAX_SHORT) / (u32_width);
}
/* Two YUV420 rows are computed at each pass */
for (u32_row = u32_height; u32_row != 0; u32_row -=2)
{
/* Set pointers to the beginning of the row for each input image1 plane */
pu8_data_Y_current1 = pu8_data_Y_start1;
pu8_data_U1 = pu8_data_U_start1;
pu8_data_V1 = pu8_data_V_start1;
/* Set pointers to the beginning of the row for each input image2 plane */
pu8_data_Y_current2 = pu8_data_Y_start2;
pu8_data_U2 = pu8_data_U_start2;
pu8_data_V2 = pu8_data_V_start2;
/* Set pointers to the beginning of the row for each output image plane */
pu8_data_Y_current3 = pu8_data_Y_start3;
pu8_data_U3 = pu8_data_U_start3;
pu8_data_V3 = pu8_data_V_start3;
/* Set pointers to the beginning of the next row for image luma plane */
pu8_data_Y_next1 = pu8_data_Y_current1 + u32_stride_Y1;
pu8_data_Y_next2 = pu8_data_Y_current2 + u32_stride_Y2;
pu8_data_Y_next3 = pu8_data_Y_current3 + u32_stride_Y3;
/* Initialise blendfactor */
u32_blendfactor = u32_startA;
/* Blendfactor Increment accumulator */
u32_x_accum = 0;
/* Loop on each column of the output image */
for (u32_col = u32_width; u32_col != 0 ; u32_col -=2)
{
/* Update the blending factor */
u32_blendfactor = u32_startA + (u32_x_accum >> 16);
/* Get Luma value (x,y) of input Image1 */
u32_Y1 = *pu8_data_Y_current1++;
/* Get chrominance2 value */
u32_U1 = *pu8_data_U1++;
u32_V1 = *pu8_data_V1++;
/* Get Luma value (x,y) of input Image2 */
u32_Y2 = *pu8_data_Y_current2++;
/* Get chrominance2 value */
u32_U2 = *pu8_data_U2++;
u32_V2 = *pu8_data_V2++;
/* Compute Luma value (x,y) of Output image */
*pu8_data_Y_current3++ = (UInt8)((u32_blendfactor * u32_Y2 +
(1024 - u32_blendfactor)*u32_Y1) >> 10);
/* Compute chroma(U) value of Output image */
*pu8_data_U3++ = (UInt8)((u32_blendfactor * u32_U2 +
(1024 - u32_blendfactor)*u32_U1) >> 10);
/* Compute chroma(V) value of Output image */
*pu8_data_V3++ = (UInt8)((u32_blendfactor * u32_V2 +
(1024 - u32_blendfactor)*u32_V1) >> 10);
/* Get Luma value (x,y+1) of input Image1 */
u32_Y1 = *pu8_data_Y_next1++;
/* Get Luma value (x,y+1) of input Image2 */
u32_Y2 = *pu8_data_Y_next2++;
/* Compute Luma value (x,y+1) of Output image*/
*pu8_data_Y_next3++ = (UInt8)((u32_blendfactor * u32_Y2 +
(1024 - u32_blendfactor)*u32_Y1) >> 10);
/* Update accumulator */
u32_x_accum += u32_blend_inc;
/* Update the blending factor */
u32_blendfactor = u32_startA + (u32_x_accum >> 16);
/* Get Luma value (x+1,y) of input Image1 */
u32_Y1 = *pu8_data_Y_current1++;
/* Get Luma value (x+1,y) of input Image2 */
u32_Y2 = *pu8_data_Y_current2++;
/* Compute Luma value (x+1,y) of Output image*/
*pu8_data_Y_current3++ = (UInt8)((u32_blendfactor * u32_Y2 +
(1024 - u32_blendfactor)*u32_Y1) >> 10);
/* Get Luma value (x+1,y+1) of input Image1 */
u32_Y1 = *pu8_data_Y_next1++;
/* Get Luma value (x+1,y+1) of input Image2 */
u32_Y2 = *pu8_data_Y_next2++;
/* Compute Luma value (x+1,y+1) of Output image*/
*pu8_data_Y_next3++ = (UInt8)((u32_blendfactor * u32_Y2 +
(1024 - u32_blendfactor)*u32_Y1) >> 10);
/* Update accumulator */
u32_x_accum += u32_blend_inc;
/* Working pointers are incremented just after each storage */
}/* End of row scanning */
/* Update working pointer of input image1 for next row */
pu8_data_Y_start1 += u32_stride2_Y1;
pu8_data_U_start1 += u32_stride_U1;
pu8_data_V_start1 += u32_stride_V1;
/* Update working pointer of input image2 for next row */
pu8_data_Y_start2 += u32_stride2_Y2;
pu8_data_U_start2 += u32_stride_U2;
pu8_data_V_start2 += u32_stride_V2;
/* Update working pointer of output image for next row */
pu8_data_Y_start3 += u32_stride2_Y3;
pu8_data_U_start3 += u32_stride_U3;
pu8_data_V_start3 += u32_stride_V3;
}/* End of column scanning */
return M4VIFI_OK;
}
/* End of file M4VIFI_ImageBlendingonYUV420.c */