libhevc-mirror/decoder/ihevcd_fmt_conv.c
Ram Mohan M 38e622bf6a
Some checks are pending
CMake / build (cmake, aarch64-linux-gnu-gcc, -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/aarch64_toolchain.cmake, aarch64-linux-gnu-g++, ubuntu-latest-cross-aarch64-cmake, ubuntu-latest) (push) Waiting to run
CMake / build (cmake, arm-linux-gnueabihf-gcc, -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/aarch32_toolchain.cmake, arm-linux-gnueabihf-g++, ubuntu-latest-cross-aarch32-cmake, ubuntu-latest) (push) Waiting to run
CMake / build (cmake, clang, , clang++, macos-latest-clang-cmake, macos-latest) (push) Waiting to run
CMake / build (cmake, clang, , clang++, ubuntu-24.04-arm-clang-cmake, ubuntu-24.04-arm) (push) Waiting to run
CMake / build (cmake, clang, , clang++, ubuntu-latest-clang-cmake, ubuntu-latest) (push) Waiting to run
CMake / build (cmake, clang, -DSANITIZE=fuzzer-no-link,address, clang++, ubuntu-latest-clang-cmake-asan-fuzzer, ubuntu-latest) (push) Waiting to run
CMake / build (cmake, clang, -G Ninja, clang++, ubuntu-latest-clang-cmake-ninja, ubuntu-latest) (push) Waiting to run
CMake / build (cmake, gcc, , g++, ubuntu-latest-gcc-cmake, ubuntu-latest) (push) Waiting to run
hevcdec: update lib for chroma format idc 422
- updated parser for 422 specific syntax elements
- updated iqitrecon module to handle 422 subtu's. Verified functionality
  for intra only slices
- add support 422 i/o
- restrict combinations of output chroma format and internal chroma
  format allowed. That is, for a given chroma format idc not all output
  color formats are supported. The output format can now be either same
  as internal color format or 420p.

Test: ./hevcdec
Change-Id: I9dbf5c141aceb8ffcbe063aa35856eeed11e3d4f
2026-03-04 15:39:55 -08:00

1008 lines
31 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
*
* Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
*
* 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
* ihevcd_fmt_conv.c
*
* @brief
* Contains functions for format conversion or frame copy of output buffer
*
* @author
* Harish
*
* @par List of Functions:
*
* @remarks
* None
*
*******************************************************************************
*/
/*****************************************************************************/
/* File Includes */
/*****************************************************************************/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "ihevc_typedefs.h"
#include "iv.h"
#include "ivd.h"
#include "ihevcd_cxa.h"
#include "ithread.h"
#include "ihevc_defs.h"
#include "ihevc_debug.h"
#include "ihevc_structs.h"
#include "ihevc_macros.h"
#include "ihevc_platform_macros.h"
#include "ihevc_cabac_tables.h"
#include "ihevc_disp_mgr.h"
#include "ihevcd_defs.h"
#include "ihevcd_function_selector.h"
#include "ihevcd_structs.h"
#include "ihevcd_error.h"
#include "ihevcd_nal.h"
#include "ihevcd_bitstream.h"
#include "ihevcd_fmt_conv.h"
#include "ihevcd_profile.h"
/* SIMD variants of format conversion modules do not support width less than 32 */
#define MIN_FMT_CONV_SIMD_WIDTH 32
/**
*******************************************************************************
*
* @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 ihevcd_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 400 buffer
*
* @par Description
* Function used from copying a 400 buffer
*
* @param[in] pu1_y_src
* Input Y pointer
*
* @param[in] pu1_y_dst
* Output Y pointer
*
* @param[in] wd
* Width
*
* @param[in] ht
* Height
*
* @param[in] src_y_strd
* Input Y Stride
*
* @param[in] dst_y_strd
* Output Y 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 ihevcd_fmt_conv_luma_copy(UWORD8 *pu1_y_src,
UWORD8 *pu1_y_dst,
WORD32 wd,
WORD32 ht,
WORD32 src_y_strd,
WORD32 dst_y_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;
}
return;
}
/**
*******************************************************************************
*
* @brief Function to convert a YUV 4:0:0 buffer to YUV 4:2:0 buffer
*
* @par Description
* This function handles the format conversion from a 4:0:0 input buffer to a
* 4:2:0 output buffer. It copies the Luma (Y) plane directly and synthesizes
* the Chroma (U and V) planes by initializing them to a neutral gray value (128).
*
* @param[in] pu1_y_src
*   Input Y pointer
*
* @param[out] pu1_y_dst_tmp
*   Output Y pointer
*
* @param[out] pu1_u_dst_tmp
*   Output Chroma U pointer
*
* @param[out] pu1_v_dst_tmp
*   Output Chroma V pointer
*
* @param[in] ps_codec
*   Pointer to the codec structure
*
* @param[in] num_rows
*   Number of rows (height) to process.
*
* @returns None
*
* @remarks The Chroma (U and V) planes are initialized to 128, which represents
* a neutral gray in 8-bit YUV, effectively 'zeroing out' the color information
* present in the 4:0:0 (grayscale) source. The Luma plane is copied using
* ihevcd_fmt_conv_400_to_400.
*
*******************************************************************************
*/
void ihevcd_fmt_conv_400_to_420p(UWORD8 *pu1_y_src,
UWORD8 *pu1_y_dst,
UWORD8 *pu1_u_dst,
UWORD8 *pu1_v_dst,
WORD32 wd,
WORD32 ht,
WORD32 src_y_strd,
WORD32 dst_y_strd,
WORD32 dst_uv_strd)
{
ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
for(int i = 0; i < ht / 2; i++)
{
memset(pu1_u_dst, 128, wd / 2);
memset(pu1_v_dst, 128, wd / 2);
pu1_u_dst += dst_uv_strd;
pu1_v_dst += dst_uv_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 ihevcd_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 ihevcd_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;
}
/**
*******************************************************************************
*
* @brief Function to convert a YUV 4:4:4 sp buffer to YUV 4:4:4 planar buffer
*
* @par Description
* This function handles the format conversion from a 4:4:4 semi planar input buffer
* to a 4:4:4 planar output buffer.
*
* @param[in] pu1_y_src
* Input Y pointer
*
* @param[in] pu1_uv_src
* Input UV pointer (UV is interleaved)
*
* @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 U or V stride
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
void ihevcd_fmt_conv_444sp_to_444p(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)
{
ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
/* de-interleave U and V and copy to destination */
UWORD8 *pu1_u_src = (UWORD8*)pu1_uv_src;
UWORD8 *pu1_v_src = (UWORD8*)pu1_uv_src + 1;
for(WORD32 i = 0; i < ht; i++)
{
for(WORD32 j = 0; j < wd; j++)
{
pu1_u_dst[j] = pu1_u_src[j * 2];
pu1_v_dst[j] = pu1_v_src[j * 2];
}
pu1_u_dst += dst_uv_strd;
pu1_v_dst += dst_uv_strd;
pu1_u_src += src_uv_strd;
pu1_v_src += src_uv_strd;
}
return;
}
void ihevcd_fmt_conv_444sp_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)
{
ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
for(WORD32 i = 0; i < ht; i += 2)
{
for(WORD32 j = 0; j < wd; j += 2)
{
pu1_u_dst[j / 2] = pu1_uv_src[j * 2];
pu1_v_dst[j / 2] = pu1_uv_src[j * 2 + 1];
}
pu1_u_dst += dst_uv_strd;
pu1_v_dst += dst_uv_strd;
pu1_uv_src += (src_uv_strd * 2);
}
return;
}
void ihevcd_fmt_conv_422sp_to_422p(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)
{
UWORD8 *pu1_u_src, *pu1_v_src;
WORD32 i, j;
ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
pu1_u_src = (UWORD8 *)pu1_uv_src;
pu1_v_src = (UWORD8 *)pu1_uv_src + 1;
for(i = 0; i < ht; i++)
{
for(j = 0; j < (wd >> 1); j++)
{
pu1_u_dst[j] = pu1_u_src[j * 2];
pu1_v_dst[j] = pu1_v_src[j * 2];
}
pu1_u_dst += dst_uv_strd;
pu1_v_dst += dst_uv_strd;
pu1_u_src += src_uv_strd;
pu1_v_src += src_uv_strd;
}
return;
}
void ihevcd_fmt_conv_422sp_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)
{
ihevcd_fmt_conv_luma_copy(pu1_y_src, pu1_y_dst, wd, ht, src_y_strd, dst_y_strd);
for(WORD32 i = 0; i < ht; i++)
{
for(WORD32 j = 0; j < wd; j += 2)
{
pu1_u_dst[j / 2] = pu1_uv_src[j * 2];
pu1_v_dst[j / 2] = pu1_uv_src[j * 2 + 1];
}
pu1_u_dst += dst_uv_strd;
pu1_v_dst += dst_uv_strd;
pu1_uv_src += src_uv_strd;
}
return;
}
/**
*******************************************************************************
*
* @brief Function used from format conversion or frame copy
*
* @par Description
* Function used from copying or converting a reference frame to display buffer
* in non shared mode
*
* @param[in] pu1_y_dst
* Output Y pointer
*
* @param[in] pu1_u_dst
* Output U/UV pointer ( UV is interleaved in the same format as that of input)
*
* @param[in] pu1_v_dst
* Output V pointer ( used in 420P output case)
*
* @param[in] blocking
* To indicate whether format conversion should wait till frame is reconstructed
* and then return after complete copy is done. To be set to 1 when called at the
* end of frame processing and set to 0 when called between frame processing modules
* in order to utilize available MCPS
*
* @returns Error from IHEVCD_ERROR_T
*
*******************************************************************************
*/
IHEVCD_ERROR_T ihevcd_fmt_conv(codec_t *ps_codec,
process_ctxt_t *ps_proc,
UWORD8 *pu1_y_dst,
UWORD8 *pu1_u_dst,
UWORD8 *pu1_v_dst,
WORD32 cur_row,
WORD32 num_rows)
{
IHEVCD_ERROR_T ret = (IHEVCD_ERROR_T)IHEVCD_SUCCESS;
pic_buf_t *ps_disp_pic;
UWORD8 *pu1_y_src, *pu1_uv_src;
UWORD8 *pu1_y_dst_tmp, *pu1_uv_dst_tmp;
UWORD8 *pu1_u_dst_tmp, *pu1_v_dst_tmp;
WORD32 is_u_first;
UWORD8 *pu1_luma;
UWORD8 *pu1_chroma;
sps_t *ps_sps;
WORD32 disable_luma_copy;
WORD32 crop_unit_x, crop_unit_y;
WORD32 h_samp_factor, v_samp_factor;
WORD32 src_chroma_pixel_strd = 2;
WORD32 src_chroma_row_stride;
if(0 == num_rows)
return ret;
/* In case processing is disabled, then no need to format convert/copy */
PROFILE_DISABLE_FMT_CONV();
ps_sps = ps_proc->ps_sps;
h_samp_factor = (CHROMA_FMT_IDC_YUV444 == ps_sps->i1_chroma_format_idc) ? 1 : 2;
v_samp_factor = (CHROMA_FMT_IDC_YUV420 == ps_sps->i1_chroma_format_idc) ? 2 : 1;
crop_unit_x = 1;
crop_unit_y = 1;
if(CHROMA_FMT_IDC_YUV420 == ps_sps->i1_chroma_format_idc)
{
crop_unit_x = 2;
crop_unit_y = 2;
}
else if(CHROMA_FMT_IDC_YUV422 == ps_sps->i1_chroma_format_idc)
{
crop_unit_x = 2;
crop_unit_y = 1;
}
ps_disp_pic = ps_codec->ps_disp_buf;
pu1_luma = ps_disp_pic->pu1_luma;
if(CHROMA_FMT_IDC_MONOCHROME != ps_sps->i1_chroma_format_idc)
{
pu1_chroma = ps_disp_pic->pu1_chroma;
}
/* Take care of cropping */
pu1_luma += ps_codec->i4_strd * ps_sps->i2_pic_crop_top_offset * crop_unit_y + ps_sps->i2_pic_crop_left_offset * crop_unit_x;
src_chroma_row_stride = (ps_codec->i4_strd * src_chroma_pixel_strd / h_samp_factor);
if(CHROMA_FMT_IDC_MONOCHROME != ps_sps->i1_chroma_format_idc)
{
pu1_chroma += (ps_sps->i2_pic_crop_top_offset * src_chroma_row_stride)
+ ps_sps->i2_pic_crop_left_offset * src_chroma_pixel_strd;
}
is_u_first = (IV_YUV_420SP_UV == ps_codec->e_ref_chroma_fmt) ? 1 : 0;
/* In case of 420P output luma copy is disabled for shared mode */
disable_luma_copy = 0;
if(1 == ps_codec->i4_share_disp_buf)
{
disable_luma_copy = 1;
}
{
pu1_y_src = pu1_luma + cur_row * ps_codec->i4_strd;
if(CHROMA_FMT_IDC_MONOCHROME != ps_sps->i1_chroma_format_idc)
{
pu1_uv_src = pu1_chroma + ((cur_row / v_samp_factor) * src_chroma_row_stride);
}
/* In case of shared mode, with 420P output, get chroma destination */
if((1 == ps_codec->i4_share_disp_buf) && (IV_YUV_420P == ps_codec->e_chroma_fmt))
{
WORD32 i;
for(i = 0; i < ps_codec->i4_share_disp_buf_cnt; i++)
{
WORD32 diff = ps_disp_pic->pu1_luma - ps_codec->s_disp_buffer[i].pu1_bufs[0];
if(diff == (ps_codec->i4_strd * PAD_TOP + PAD_LEFT))
{
pu1_u_dst = ps_codec->s_disp_buffer[i].pu1_bufs[1];
pu1_u_dst += (ps_codec->i4_strd * PAD_TOP) / 4 + (PAD_LEFT / 2);
pu1_v_dst = ps_codec->s_disp_buffer[i].pu1_bufs[2];
pu1_v_dst += (ps_codec->i4_strd * PAD_TOP) / 4 + (PAD_LEFT / 2);
break;
}
}
}
pu1_y_dst_tmp = pu1_y_dst + cur_row * ps_codec->i4_disp_strd;
if(IV_YUV_444P == ps_codec->e_chroma_fmt)
{
pu1_u_dst_tmp = pu1_u_dst + cur_row * ps_codec->i4_disp_strd;
pu1_v_dst_tmp = pu1_v_dst + cur_row * ps_codec->i4_disp_strd;
}
else if(IV_YUV_422P == ps_codec->e_chroma_fmt)
{
pu1_u_dst_tmp = pu1_u_dst + cur_row * ps_codec->i4_disp_strd / 2;
pu1_v_dst_tmp = pu1_v_dst + cur_row * ps_codec->i4_disp_strd / 2;
}
else if(IV_YUV_420P == ps_codec->e_chroma_fmt)
{
pu1_u_dst_tmp = pu1_u_dst + (cur_row / 2) * ps_codec->i4_disp_strd / 2;
pu1_v_dst_tmp = pu1_v_dst + (cur_row / 2) * ps_codec->i4_disp_strd / 2;
}
else if(IV_YUV_420SP_UV == ps_codec->e_chroma_fmt
|| IV_YUV_420SP_VU == ps_codec->e_chroma_fmt)
{
pu1_uv_dst_tmp = pu1_u_dst + (cur_row / 2) * ps_codec->i4_disp_strd;
}
/* In case of multi threaded implementation, format conversion might be called
* before reconstruction is completed. If the frame being converted/copied
* is same as the frame being reconstructed,
* Check how many rows can be format converted
* Convert those many rows and then check for remaining rows and so on
*/
if((0 == ps_codec->i4_flush_mode) && (ps_codec->i4_disp_buf_id == ps_proc->i4_cur_pic_buf_id) && (1 < ps_codec->i4_num_cores))
{
WORD32 idx;
UWORD8 *pu1_buf;
WORD32 status;
WORD32 last_row = cur_row + num_rows;
WORD32 last_ctb_y;
UWORD32 ctb_in_row;
while(1)
{
last_row = cur_row + MAX(num_rows, (1 << ps_sps->i1_log2_ctb_size)) +
ps_sps->i2_pic_crop_top_offset * crop_unit_y;
last_ctb_y = (last_row >> ps_sps->i1_log2_ctb_size) - 1;
/* Since deblocking works with a shift of -4, -4 ,wait till next CTB row is processed */
last_ctb_y++;
/* In case of a conformance window, an extra wait of one row might be needed */
last_ctb_y++;
last_ctb_y = MIN(last_ctb_y, (ps_sps->i2_pic_ht_in_ctb - 1));
idx = (last_ctb_y * ps_sps->i2_pic_wd_in_ctb);
/*Check if the row below is completely processed before proceeding with format conversion*/
status = 1;
for(ctb_in_row = 0; (WORD32)ctb_in_row < ps_sps->i2_pic_wd_in_ctb; ctb_in_row++)
{
pu1_buf = (ps_codec->pu1_proc_map + idx + ctb_in_row);
status &= *pu1_buf;
}
if(status)
{
break;
}
else
{
ithread_yield();
}
}
}
if((IV_YUV_420SP_UV == ps_codec->e_chroma_fmt) || (IV_YUV_420SP_VU == ps_codec->e_chroma_fmt))
{
if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV420)
{
ihevcd_fmt_conv_420sp_to_420sp_ft *fmt_conv_fptr;
if(ps_codec->i4_disp_wd >= MIN_FMT_CONV_SIMD_WIDTH)
{
fmt_conv_fptr = ps_codec->s_func_selector.ihevcd_fmt_conv_420sp_to_420sp_fptr;
}
else
{
fmt_conv_fptr = ihevcd_fmt_conv_420sp_to_420sp;
}
fmt_conv_fptr(pu1_y_src, pu1_uv_src,
pu1_y_dst_tmp, pu1_uv_dst_tmp,
ps_codec->i4_disp_wd, num_rows,
ps_codec->i4_strd, ps_codec->i4_strd,
ps_codec->i4_disp_strd, ps_codec->i4_disp_strd);
}
}
else if(IV_GRAY == ps_codec->e_chroma_fmt)
{
ihevcd_fmt_conv_luma_copy(pu1_y_src,
pu1_y_dst_tmp,
ps_codec->i4_disp_wd, num_rows,
ps_codec->i4_strd,
ps_codec->i4_disp_strd);
}
else if(IV_YUV_444P == ps_codec->e_chroma_fmt)
{
if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV444)
{
ps_codec->s_func_selector.ihevcd_fmt_conv_444sp_to_444p_fptr(
pu1_y_src, pu1_uv_src,
pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
ps_codec->i4_disp_wd, num_rows,
ps_codec->i4_strd, src_chroma_row_stride,
ps_codec->i4_disp_strd, ps_codec->i4_disp_strd);
}
}
else if(IV_YUV_422P == ps_codec->e_chroma_fmt)
{
if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV422)
{
ihevcd_fmt_conv_422sp_to_422p(pu1_y_src, pu1_uv_src,
pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
ps_codec->i4_disp_wd, num_rows,
ps_codec->i4_strd, ps_codec->i4_strd,
ps_codec->i4_disp_strd, (ps_codec->i4_disp_strd / 2));
}
}
else if(IV_YUV_420P == ps_codec->e_chroma_fmt)
{
if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_MONOCHROME)
{
ihevcd_fmt_conv_400_to_420p(pu1_y_src,
pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
ps_codec->i4_disp_wd, num_rows,
ps_codec->i4_strd,
ps_codec->i4_disp_strd, (ps_codec->i4_disp_strd / 2));
}
else if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV420)
{
ihevcd_fmt_conv_420sp_to_420p_ft *fmt_conv_fptr;
if(ps_codec->i4_disp_wd >= MIN_FMT_CONV_SIMD_WIDTH)
{
fmt_conv_fptr = ps_codec->s_func_selector.ihevcd_fmt_conv_420sp_to_420p_fptr;
}
else
{
fmt_conv_fptr = ihevcd_fmt_conv_420sp_to_420p;
}
if(0 == disable_luma_copy)
{
// copy luma
WORD32 i;
WORD32 num_cols = ps_codec->i4_disp_wd;
for(i = 0; i < num_rows; i++)
{
memcpy(pu1_y_dst_tmp, pu1_y_src, num_cols);
pu1_y_dst_tmp += ps_codec->i4_disp_strd;
pu1_y_src += ps_codec->i4_strd;
}
disable_luma_copy = 1;
}
fmt_conv_fptr(pu1_y_src, pu1_uv_src,
pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
ps_codec->i4_disp_wd, num_rows,
ps_codec->i4_strd, ps_codec->i4_strd,
ps_codec->i4_disp_strd, (ps_codec->i4_disp_strd / 2),
is_u_first,
disable_luma_copy);
}
else if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV444)
{
ihevcd_fmt_conv_444sp_to_420p(pu1_y_src, pu1_uv_src,
pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
ps_codec->i4_disp_wd, num_rows,
ps_codec->i4_strd, src_chroma_row_stride,
ps_codec->i4_disp_strd, ps_codec->i4_disp_strd / 2);
}
else if(ps_sps->i1_chroma_format_idc == CHROMA_FMT_IDC_YUV422)
{
ihevcd_fmt_conv_422sp_to_420p(pu1_y_src, pu1_uv_src,
pu1_y_dst_tmp, pu1_u_dst_tmp, pu1_v_dst_tmp,
ps_codec->i4_disp_wd, num_rows,
ps_codec->i4_strd, src_chroma_row_stride,
ps_codec->i4_disp_strd, ps_codec->i4_disp_strd / 2);
}
}
}
return (ret);
}