/****************************************************************************** * * Copyright (C) 2015 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. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ /*****************************************************************************/ /* */ /* File Name : ih264d_format_conv.c */ /* */ /* Description : Contains functions needed to convert the images in */ /* different color spaces to yuv 422i color space */ /* */ /* */ /* Issues / Problems : None */ /* */ /* Revision History : */ /* */ /* DD MM YYYY Author(s) Changes (Describe the changes made) */ /* 28 08 2007 Naveen Kumar T Draft */ /* */ /*****************************************************************************/ /*****************************************************************************/ /* File Includes */ /*****************************************************************************/ /* System include files */ #include /* User include files */ #include "ih264_typedefs.h" #include "iv.h" #include "ih264_macros.h" #include "ih264_platform_macros.h" #include "ih264d_structs.h" #include "ih264d_format_conv.h" #include "ih264d_defs.h" #ifdef LOGO_EN #include "ih264d_ittiam_logo.h" #define INSERT_LOGO(pu1_buf_y,pu1_buf_u,pu1_buf_v, u4_stride, u4_x_pos, u4_y_pos, u4_yuv_fmt, u4_disp_wd, u4_disp_ht) \ ih264d_insert_logo(pu1_buf_y,pu1_buf_u,pu1_buf_v, u4_stride,\ u4_x_pos, u4_y_pos, u4_yuv_fmt, u4_disp_wd, u4_disp_ht) #else #define INSERT_LOGO(pu1_buf_y,pu1_buf_u,pu1_buf_v, u4_stride, u4_x_pos, u4_y_pos, u4_yuv_fmt, u4_disp_wd, u4_disp_ht) #endif /** ******************************************************************************* * * @brief Function used from copying a 420SP buffer * * @par Description * Function used from copying a 420SP buffer * * @param[in] pu1_y_src * Input Y pointer * * @param[in] pu1_uv_src * Input UV pointer (UV is interleaved either in UV or VU format) * * @param[in] pu1_y_dst * Output Y pointer * * @param[in] pu1_uv_dst * Output UV pointer (UV is interleaved in the same format as that of input) * * @param[in] wd * Width * * @param[in] ht * Height * * @param[in] src_y_strd * Input Y Stride * * @param[in] src_uv_strd * Input UV stride * * @param[in] dst_y_strd * Output Y stride * * @param[in] dst_uv_strd * Output UV stride * * @returns None * * @remarks In case there is a need to perform partial frame copy then * by passion appropriate source and destination pointers and appropriate * values for wd and ht it can be done * ******************************************************************************* */ void ih264d_fmt_conv_420sp_to_rgb565(UWORD8 *pu1_y_src, UWORD8 *pu1_uv_src, UWORD16 *pu2_rgb_dst, WORD32 wd, WORD32 ht, WORD32 src_y_strd, WORD32 src_uv_strd, WORD32 dst_strd, WORD32 is_u_first) { WORD16 i2_r, i2_g, i2_b; UWORD32 u4_r, u4_g, u4_b; WORD16 i2_i, i2_j; UWORD8 *pu1_y_src_nxt; UWORD16 *pu2_rgb_dst_next_row; UWORD8 *pu1_u_src, *pu1_v_src; if(is_u_first) { pu1_u_src = (UWORD8 *)pu1_uv_src; pu1_v_src = (UWORD8 *)pu1_uv_src + 1; } else { pu1_u_src = (UWORD8 *)pu1_uv_src + 1; pu1_v_src = (UWORD8 *)pu1_uv_src; } pu1_y_src_nxt = pu1_y_src + src_y_strd; pu2_rgb_dst_next_row = pu2_rgb_dst + dst_strd; for(i2_i = 0; i2_i < (ht >> 1); i2_i++) { for(i2_j = (wd >> 1); i2_j > 0; i2_j--) { i2_b = ((*pu1_u_src - 128) * COEFF4 >> 13); i2_g = ((*pu1_u_src - 128) * COEFF2 + (*pu1_v_src - 128) * COEFF3) >> 13; i2_r = ((*pu1_v_src - 128) * COEFF1) >> 13; pu1_u_src += 2; pu1_v_src += 2; /* pixel 0 */ /* B */ u4_b = CLIP_U8(*pu1_y_src + i2_b); u4_b >>= 3; /* G */ u4_g = CLIP_U8(*pu1_y_src + i2_g); u4_g >>= 2; /* R */ u4_r = CLIP_U8(*pu1_y_src + i2_r); u4_r >>= 3; pu1_y_src++; *pu2_rgb_dst++ = ((u4_r << 11) | (u4_g << 5) | u4_b); /* pixel 1 */ /* B */ u4_b = CLIP_U8(*pu1_y_src + i2_b); u4_b >>= 3; /* G */ u4_g = CLIP_U8(*pu1_y_src + i2_g); u4_g >>= 2; /* R */ u4_r = CLIP_U8(*pu1_y_src + i2_r); u4_r >>= 3; pu1_y_src++; *pu2_rgb_dst++ = ((u4_r << 11) | (u4_g << 5) | u4_b); /* pixel 2 */ /* B */ u4_b = CLIP_U8(*pu1_y_src_nxt + i2_b); u4_b >>= 3; /* G */ u4_g = CLIP_U8(*pu1_y_src_nxt + i2_g); u4_g >>= 2; /* R */ u4_r = CLIP_U8(*pu1_y_src_nxt + i2_r); u4_r >>= 3; pu1_y_src_nxt++; *pu2_rgb_dst_next_row++ = ((u4_r << 11) | (u4_g << 5) | u4_b); /* pixel 3 */ /* B */ u4_b = CLIP_U8(*pu1_y_src_nxt + i2_b); u4_b >>= 3; /* G */ u4_g = CLIP_U8(*pu1_y_src_nxt + i2_g); u4_g >>= 2; /* R */ u4_r = CLIP_U8(*pu1_y_src_nxt + i2_r); u4_r >>= 3; pu1_y_src_nxt++; *pu2_rgb_dst_next_row++ = ((u4_r << 11) | (u4_g << 5) | u4_b); } pu1_u_src = pu1_u_src + src_uv_strd - wd; pu1_v_src = pu1_v_src + src_uv_strd - wd; pu1_y_src = pu1_y_src + (src_y_strd << 1) - wd; pu1_y_src_nxt = pu1_y_src_nxt + (src_y_strd << 1) - wd; pu2_rgb_dst = pu2_rgb_dst_next_row - wd + dst_strd; pu2_rgb_dst_next_row = pu2_rgb_dst_next_row + (dst_strd << 1) - wd; } } void ih264d_fmt_conv_420sp_to_rgba8888(UWORD8 *pu1_y_src, UWORD8 *pu1_uv_src, UWORD32 *pu4_rgba_dst, WORD32 wd, WORD32 ht, WORD32 src_y_strd, WORD32 src_uv_strd, WORD32 dst_strd, WORD32 is_u_first) { WORD16 i2_r, i2_g, i2_b; UWORD32 u4_r, u4_g, u4_b; WORD16 i2_i, i2_j; UWORD8 *pu1_y_src_nxt; UWORD32 *pu4_rgba_dst_next_row; UWORD8 *pu1_u_src, *pu1_v_src; if(is_u_first) { pu1_u_src = (UWORD8 *)pu1_uv_src; pu1_v_src = (UWORD8 *)pu1_uv_src + 1; } else { pu1_u_src = (UWORD8 *)pu1_uv_src + 1; pu1_v_src = (UWORD8 *)pu1_uv_src; } pu1_y_src_nxt = pu1_y_src + src_y_strd; pu4_rgba_dst_next_row = pu4_rgba_dst + dst_strd; for(i2_i = 0; i2_i < (ht >> 1); i2_i++) { for(i2_j = (wd >> 1); i2_j > 0; i2_j--) { i2_b = ((*pu1_u_src - 128) * COEFF4 >> 13); i2_g = ((*pu1_u_src - 128) * COEFF2 + (*pu1_v_src - 128) * COEFF3) >> 13; i2_r = ((*pu1_v_src - 128) * COEFF1) >> 13; pu1_u_src += 2; pu1_v_src += 2; /* pixel 0 */ /* B */ u4_b = CLIP_U8(*pu1_y_src + i2_b); /* G */ u4_g = CLIP_U8(*pu1_y_src + i2_g); /* R */ u4_r = CLIP_U8(*pu1_y_src + i2_r); pu1_y_src++; *pu4_rgba_dst++ = ((u4_r << 16) | (u4_g << 8) | (u4_b << 0)); /* pixel 1 */ /* B */ u4_b = CLIP_U8(*pu1_y_src + i2_b); /* G */ u4_g = CLIP_U8(*pu1_y_src + i2_g); /* R */ u4_r = CLIP_U8(*pu1_y_src + i2_r); pu1_y_src++; *pu4_rgba_dst++ = ((u4_r << 16) | (u4_g << 8) | (u4_b << 0)); /* pixel 2 */ /* B */ u4_b = CLIP_U8(*pu1_y_src_nxt + i2_b); /* G */ u4_g = CLIP_U8(*pu1_y_src_nxt + i2_g); /* R */ u4_r = CLIP_U8(*pu1_y_src_nxt + i2_r); pu1_y_src_nxt++; *pu4_rgba_dst_next_row++ = ((u4_r << 16) | (u4_g << 8) | (u4_b << 0)); /* pixel 3 */ /* B */ u4_b = CLIP_U8(*pu1_y_src_nxt + i2_b); /* G */ u4_g = CLIP_U8(*pu1_y_src_nxt + i2_g); /* R */ u4_r = CLIP_U8(*pu1_y_src_nxt + i2_r); pu1_y_src_nxt++; *pu4_rgba_dst_next_row++ = ((u4_r << 16) | (u4_g << 8) | (u4_b << 0)); } pu1_u_src = pu1_u_src + src_uv_strd - wd; pu1_v_src = pu1_v_src + src_uv_strd - wd; pu1_y_src = pu1_y_src + (src_y_strd << 1) - wd; pu1_y_src_nxt = pu1_y_src_nxt + (src_y_strd << 1) - wd; pu4_rgba_dst = pu4_rgba_dst_next_row - wd + dst_strd; pu4_rgba_dst_next_row = pu4_rgba_dst_next_row + (dst_strd << 1) - wd; } } /** ******************************************************************************* * * @brief Function used from copying a 420SP buffer * * @par Description * Function used from copying a 420SP buffer * * @param[in] pu1_y_src * Input Y pointer * * @param[in] pu1_uv_src * Input UV pointer (UV is interleaved either in UV or VU format) * * @param[in] pu1_y_dst * Output Y pointer * * @param[in] pu1_uv_dst * Output UV pointer (UV is interleaved in the same format as that of input) * * @param[in] wd * Width * * @param[in] ht * Height * * @param[in] src_y_strd * Input Y Stride * * @param[in] src_uv_strd * Input UV stride * * @param[in] dst_y_strd * Output Y stride * * @param[in] dst_uv_strd * Output UV stride * * @returns None * * @remarks In case there is a need to perform partial frame copy then * by passion appropriate source and destination pointers and appropriate * values for wd and ht it can be done * ******************************************************************************* */ void ih264d_fmt_conv_420sp_to_420sp(UWORD8 *pu1_y_src, UWORD8 *pu1_uv_src, UWORD8 *pu1_y_dst, UWORD8 *pu1_uv_dst, WORD32 wd, WORD32 ht, WORD32 src_y_strd, WORD32 src_uv_strd, WORD32 dst_y_strd, WORD32 dst_uv_strd) { UWORD8 *pu1_src, *pu1_dst; WORD32 num_rows, num_cols, src_strd, dst_strd; WORD32 i; /* copy luma */ pu1_src = (UWORD8 *)pu1_y_src; pu1_dst = (UWORD8 *)pu1_y_dst; num_rows = ht; num_cols = wd; src_strd = src_y_strd; dst_strd = dst_y_strd; for(i = 0; i < num_rows; i++) { memcpy(pu1_dst, pu1_src, num_cols); pu1_dst += dst_strd; pu1_src += src_strd; } /* copy U and V */ pu1_src = (UWORD8 *)pu1_uv_src; pu1_dst = (UWORD8 *)pu1_uv_dst; num_rows = ht >> 1; num_cols = wd; src_strd = src_uv_strd; dst_strd = dst_uv_strd; for(i = 0; i < num_rows; i++) { memcpy(pu1_dst, pu1_src, num_cols); pu1_dst += dst_strd; pu1_src += src_strd; } return; } /** ******************************************************************************* * * @brief Function used from copying a 420SP buffer * * @par Description * Function used from copying a 420SP buffer * * @param[in] pu1_y_src * Input Y pointer * * @param[in] pu1_uv_src * Input UV pointer (UV is interleaved either in UV or VU format) * * @param[in] pu1_y_dst * Output Y pointer * * @param[in] pu1_uv_dst * Output UV pointer (UV is interleaved in the same format as that of input) * * @param[in] wd * Width * * @param[in] ht * Height * * @param[in] src_y_strd * Input Y Stride * * @param[in] src_uv_strd * Input UV stride * * @param[in] dst_y_strd * Output Y stride * * @param[in] dst_uv_strd * Output UV stride * * @returns None * * @remarks In case there is a need to perform partial frame copy then * by passion appropriate source and destination pointers and appropriate * values for wd and ht it can be done * ******************************************************************************* */ void ih264d_fmt_conv_420sp_to_420sp_swap_uv(UWORD8 *pu1_y_src, UWORD8 *pu1_uv_src, UWORD8 *pu1_y_dst, UWORD8 *pu1_uv_dst, WORD32 wd, WORD32 ht, WORD32 src_y_strd, WORD32 src_uv_strd, WORD32 dst_y_strd, WORD32 dst_uv_strd) { UWORD8 *pu1_src, *pu1_dst; WORD32 num_rows, num_cols, src_strd, dst_strd; WORD32 i; /* copy luma */ pu1_src = (UWORD8 *)pu1_y_src; pu1_dst = (UWORD8 *)pu1_y_dst; num_rows = ht; num_cols = wd; src_strd = src_y_strd; dst_strd = dst_y_strd; for(i = 0; i < num_rows; i++) { memcpy(pu1_dst, pu1_src, num_cols); pu1_dst += dst_strd; pu1_src += src_strd; } /* copy U and V */ pu1_src = (UWORD8 *)pu1_uv_src; pu1_dst = (UWORD8 *)pu1_uv_dst; num_rows = ht >> 1; num_cols = wd; src_strd = src_uv_strd; dst_strd = dst_uv_strd; for(i = 0; i < num_rows; i++) { WORD32 j; for(j = 0; j < num_cols; j += 2) { pu1_dst[j + 0] = pu1_src[j + 1]; pu1_dst[j + 1] = pu1_src[j + 0]; } pu1_dst += dst_strd; pu1_src += src_strd; } return; } /** ******************************************************************************* * * @brief Function used from copying a 420SP buffer * * @par Description * Function used from copying a 420SP buffer * * @param[in] pu1_y_src * Input Y pointer * * @param[in] pu1_uv_src * Input UV pointer (UV is interleaved either in UV or VU format) * * @param[in] pu1_y_dst * Output Y pointer * * @param[in] pu1_u_dst * Output U pointer * * @param[in] pu1_v_dst * Output V pointer * * @param[in] wd * Width * * @param[in] ht * Height * * @param[in] src_y_strd * Input Y Stride * * @param[in] src_uv_strd * Input UV stride * * @param[in] dst_y_strd * Output Y stride * * @param[in] dst_uv_strd * Output UV stride * * @param[in] is_u_first * Flag to indicate if U is the first byte in input chroma part * * @returns none * * @remarks In case there is a need to perform partial frame copy then * by passion appropriate source and destination pointers and appropriate * values for wd and ht it can be done * ******************************************************************************* */ void ih264d_fmt_conv_420sp_to_420p(UWORD8 *pu1_y_src, UWORD8 *pu1_uv_src, UWORD8 *pu1_y_dst, UWORD8 *pu1_u_dst, UWORD8 *pu1_v_dst, WORD32 wd, WORD32 ht, WORD32 src_y_strd, WORD32 src_uv_strd, WORD32 dst_y_strd, WORD32 dst_uv_strd, WORD32 is_u_first, WORD32 disable_luma_copy) { UWORD8 *pu1_src, *pu1_dst; UWORD8 *pu1_u_src, *pu1_v_src; WORD32 num_rows, num_cols, src_strd, dst_strd; WORD32 i, j; if(0 == disable_luma_copy) { /* copy luma */ pu1_src = (UWORD8 *)pu1_y_src; pu1_dst = (UWORD8 *)pu1_y_dst; num_rows = ht; num_cols = wd; src_strd = src_y_strd; dst_strd = dst_y_strd; for(i = 0; i < num_rows; i++) { memcpy(pu1_dst, pu1_src, num_cols); pu1_dst += dst_strd; pu1_src += src_strd; } } /* de-interleave U and V and copy to destination */ if(is_u_first) { pu1_u_src = (UWORD8 *)pu1_uv_src; pu1_v_src = (UWORD8 *)pu1_uv_src + 1; } else { pu1_u_src = (UWORD8 *)pu1_uv_src + 1; pu1_v_src = (UWORD8 *)pu1_uv_src; } num_rows = ht >> 1; num_cols = wd >> 1; src_strd = src_uv_strd; dst_strd = dst_uv_strd; for(i = 0; i < num_rows; i++) { for(j = 0; j < num_cols; j++) { pu1_u_dst[j] = pu1_u_src[j * 2]; pu1_v_dst[j] = pu1_v_src[j * 2]; } pu1_u_dst += dst_strd; pu1_v_dst += dst_strd; pu1_u_src += src_strd; pu1_v_src += src_strd; } return; } /*****************************************************************************/ /* Function Name : ih264d_format_convert */ /* */ /* Description : Implements format conversion/frame copy */ /* Inputs : ps_dec - Decoder parameters */ /* Globals : None */ /* Processing : Refer bumping process in the standard */ /* Outputs : Assigns display sequence number. */ /* Returns : None */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* */ /* DD MM YYYY Author(s) Changes (Describe the changes made) */ /* 27 04 2005 NS Draft */ /* */ /*****************************************************************************/ void ih264d_format_convert(dec_struct_t *ps_dec, ivd_get_display_frame_op_t *pv_disp_op, UWORD32 u4_start_y, UWORD32 u4_num_rows_y) { UWORD32 convert_uv_only = 0; iv_yuv_buf_t *ps_op_frm; UWORD8 *pu1_y_src, *pu1_uv_src; UWORD32 start_uv = u4_start_y >> 1; if(1 == pv_disp_op->u4_error_code) return; ps_op_frm = &(ps_dec->s_disp_frame_info); /* Requires u4_start_y and u4_num_rows_y to be even */ if(u4_start_y & 1) { return; } if((1 == ps_dec->u4_share_disp_buf) && (pv_disp_op->e_output_format == IV_YUV_420SP_UV)) { return; } pu1_y_src = (UWORD8 *)ps_op_frm->pv_y_buf; pu1_y_src += u4_start_y * ps_op_frm->u4_y_strd, pu1_uv_src = (UWORD8 *)ps_op_frm->pv_u_buf; pu1_uv_src += start_uv * ps_op_frm->u4_u_strd; if(pv_disp_op->e_output_format == IV_YUV_420P) { UWORD8 *pu1_y_dst, *pu1_u_dst, *pu1_v_dst; IV_COLOR_FORMAT_T e_output_format = pv_disp_op->e_output_format; if(0 == ps_dec->u4_share_disp_buf) { convert_uv_only = 0; } else { convert_uv_only = 1; } pu1_y_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_y_buf; pu1_y_dst += u4_start_y * pv_disp_op->s_disp_frm_buf.u4_y_strd; pu1_u_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_u_buf; pu1_u_dst += start_uv * pv_disp_op->s_disp_frm_buf.u4_u_strd; pu1_v_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_v_buf; pu1_v_dst += start_uv * pv_disp_op->s_disp_frm_buf.u4_v_strd; ih264d_fmt_conv_420sp_to_420p(pu1_y_src, pu1_uv_src, pu1_y_dst, pu1_u_dst, pu1_v_dst, ps_op_frm->u4_y_wd, u4_num_rows_y, ps_op_frm->u4_y_strd, ps_op_frm->u4_u_strd, pv_disp_op->s_disp_frm_buf.u4_y_strd, pv_disp_op->s_disp_frm_buf.u4_u_strd, 1, convert_uv_only); } else if((pv_disp_op->e_output_format == IV_YUV_420SP_UV) || (pv_disp_op->e_output_format == IV_YUV_420SP_VU)) { UWORD8* pu1_y_dst, *pu1_uv_dst; pu1_y_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_y_buf; pu1_y_dst += u4_start_y * pv_disp_op->s_disp_frm_buf.u4_y_strd; pu1_uv_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_u_buf; pu1_uv_dst += start_uv * pv_disp_op->s_disp_frm_buf.u4_u_strd; if(pv_disp_op->e_output_format == IV_YUV_420SP_UV) { ih264d_fmt_conv_420sp_to_420sp(pu1_y_src, pu1_uv_src, pu1_y_dst, pu1_uv_dst, ps_op_frm->u4_y_wd, u4_num_rows_y, ps_op_frm->u4_y_strd, ps_op_frm->u4_u_strd, pv_disp_op->s_disp_frm_buf.u4_y_strd, pv_disp_op->s_disp_frm_buf.u4_u_strd); } else { ih264d_fmt_conv_420sp_to_420sp_swap_uv(pu1_y_src, pu1_uv_src, pu1_y_dst, pu1_uv_dst, ps_op_frm->u4_y_wd, u4_num_rows_y, ps_op_frm->u4_y_strd, ps_op_frm->u4_u_strd, pv_disp_op->s_disp_frm_buf.u4_y_strd, pv_disp_op->s_disp_frm_buf.u4_u_strd); } } else if(pv_disp_op->e_output_format == IV_RGB_565) { UWORD16 *pu2_rgb_dst; pu2_rgb_dst = (UWORD16 *)pv_disp_op->s_disp_frm_buf.pv_y_buf; pu2_rgb_dst += u4_start_y * pv_disp_op->s_disp_frm_buf.u4_y_strd; ih264d_fmt_conv_420sp_to_rgb565(pu1_y_src, pu1_uv_src, pu2_rgb_dst, ps_op_frm->u4_y_wd, u4_num_rows_y, ps_op_frm->u4_y_strd, ps_op_frm->u4_u_strd, pv_disp_op->s_disp_frm_buf.u4_y_strd, 1); } if((u4_start_y + u4_num_rows_y) >= ps_dec->s_disp_frame_info.u4_y_ht) { INSERT_LOGO(pv_disp_op->s_disp_frm_buf.pv_y_buf, pv_disp_op->s_disp_frm_buf.pv_u_buf, pv_disp_op->s_disp_frm_buf.pv_v_buf, pv_disp_op->s_disp_frm_buf.u4_y_strd, ps_dec->u2_disp_width, ps_dec->u2_disp_height, pv_disp_op->e_output_format, ps_op_frm->u4_y_wd, ps_op_frm->u4_y_ht); } return; }