7.2 ipu_device.c分析(二)---具體函式分析
1. deinterlace_3_field函式
static bool deinterlace_3_field(struct ipu_task_entry *t)
{
return ((t->set.mode & VDI_MODE) &&
(t->input.deinterlace.motion != HIGH_MOTION));
}
2. tiled_filed_size函式
u32 field_size; static u32 tiled_filed_size(struct ipu_task_entry *t) { /* note: page_align is required by VPU hw ouput buffer */ field_size = TILED_NV12_FRAME_SIZE(t->input.width, t->input.height/2); return field_size; }
3. MODE模式
關於這個VDOA模式,在下面這個task_set結構體裡面的註釋有說明:VDOA_MODE意味著這個task任務使用vdoa,並且VDOA有兩種模式:BANDMODE和non-bandMODE模式。non-bandMODE模式將要轉化資料到記憶體中。而BANDMODE模式需要IPU硬體的同步訊號,這種模式是連上VDIC的預設模式。
先來看這個task_set結構體:
struct task_set { #define <span style="color:#FF0000;">NULL_MODE</span> 0x0 #define <span style="color:#FF0000;">IC_MODE</span> 0x1 #define <span style="color:#FF0000;">ROT_MODE</span> 0x2 #define <span style="color:#FF0000;">VDI_MODE</span> 0x4 #define <span style="color:#FF0000;">IPU_PREPROCESS_MODE_MASK</span> (IC_MODE | ROT_MODE | VDI_MODE) /* VDOA_MODE means this task use vdoa, and VDOA has two modes: * BAND MODE and non-BAND MODE. Non-band mode will do transfer data * to memory. BAND mode needs hareware sync with IPU, it is used default * if connected to VDIC. */ #define <span style="color:#FF0000;">VDOA_MODE</span> 0x8 #define <span style="color:#FF0000;">VDOA_BAND_MODE</span> 0x10 u8 mode; 。。。。。。。。。 struct stripe_setting sp_setting; };
上面紅色字型是有關MODE模式的變數,可以看到IC_MODE,ROT_MODE,VDA_MODE分別佔用u8的一位:
下面就來看下面三個函式:
3.1 only_ic函式
static bool only_ic(u8 mode)
{
mode = mode & IPU_PREPROCESS_MODE_MASK;
return ((mode == IC_MODE) || (mode == VDI_MODE));
}
可以看出來,如果mode佔用的如下紅色字型所示的任意一位的話,都可以認為是only_ic模式。
3.2 only_rot函式
static bool only_rot(u8 mode)
{
mode = mode & IPU_PREPROCESS_MODE_MASK;
return (mode == ROT_MODE);
}
這個only_rot模式,則只有mode佔用ROT位的話,才能夠認為是only_rot。
3.3ic_and_rot函式
static bool ic_and_rot(u8 mode)
{
mode = mode & IPU_PREPROCESS_MODE_MASK;
return ((mode == (IC_MODE | ROT_MODE)) ||
(mode == (VDI_MODE | ROT_MODE)));
}
這種模式如下所示:
4.need_split函式
static bool need_split(struct ipu_task_entry *t)
{
return ((t->set.split_mode != NO_SPLIT) || (t->task_no & SPLIT_MASK));
}
struct task_set {
。。。。。。。。。。
#define NO_SPLIT 0x0
#define RL_SPLIT 0x1
#define UD_SPLIT 0x2
#define LEFT_STRIPE 0x1
#define RIGHT_STRIPE 0x2
#define UP_STRIPE 0x4
#define DOWN_STRIPE 0x8
#define SPLIT_MASK 0xF
u8 split_mode;
。。。。。。。。。
struct stripe_setting sp_setting;
};
這個函式判斷的同樣是ipu_task_entry結構體中的task_set裡面的split_mode,如果這一位不等於0的話,就返回true。這個函式的意思應該是判斷一個結構體是否需要拆分,do_task,get_res_do_task,ipu_task_thread,ipu_queue_task函式中都呼叫了這個函式。
5.fmt_to_bpp函式
unsigned int fmt_to_bpp(unsigned int pixelformat)
{
u32 bpp;
switch (pixelformat) {
case IPU_PIX_FMT_RGB565:
/*interleaved 422*/
case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_UYVY:
/*non-interleaved 422*/
case IPU_PIX_FMT_YUV422P:
case IPU_PIX_FMT_YVU422P:
bpp = 16;
break;
case IPU_PIX_FMT_BGR24:
case IPU_PIX_FMT_RGB24:
case IPU_PIX_FMT_YUV444:
case IPU_PIX_FMT_YUV444P:
bpp = 24;
break;
case IPU_PIX_FMT_BGR32:
case IPU_PIX_FMT_BGRA32:
case IPU_PIX_FMT_RGB32:
case IPU_PIX_FMT_RGBA32:
case IPU_PIX_FMT_ABGR32:
bpp = 32;
break;
/*non-interleaved 420*/
case IPU_PIX_FMT_YUV420P:
case IPU_PIX_FMT_YVU420P:
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_NV12:
bpp = 12;
break;
default:
bpp = 8;
break;
}
return bpp;
}
EXPORT_SYMBOL_GPL(fmt_to_bpp);
這個函式就很簡單了,它根據pixelformat格式返回它所佔用的bit數,bitsper pixel。
6.colorspaceofpixel函式
cs_t colorspaceofpixel(int fmt)
{
switch (fmt) {
case IPU_PIX_FMT_RGB565:
case IPU_PIX_FMT_RGB666:
case IPU_PIX_FMT_BGR24:
case IPU_PIX_FMT_RGB24:
case IPU_PIX_FMT_BGRA32:
case IPU_PIX_FMT_BGR32:
case IPU_PIX_FMT_RGBA32:
case IPU_PIX_FMT_RGB32:
case IPU_PIX_FMT_ABGR32:
return RGB_CS;
break;
case IPU_PIX_FMT_UYVY:
case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
case IPU_PIX_FMT_YVU420P:
case IPU_PIX_FMT_YVU422P:
case IPU_PIX_FMT_YUV422P:
case IPU_PIX_FMT_YUV444:
case IPU_PIX_FMT_YUV444P:
case IPU_PIX_FMT_NV12:
case IPU_PIX_FMT_TILED_NV12:
case IPU_PIX_FMT_TILED_NV12F:
return YUV_CS;
break;
default:
return NULL_CS;
}
}
EXPORT_SYMBOL_GPL(colorspaceofpixel);
這個函式根據format的值返回這個format的顏色空間colorspace。顏色空間在ipu.h中定義:
typedef enum {
RGB_CS,
YUV_CS,
NULL_CS
} cs_t;
這個函式主要用在下面要介紹的need_csc函式。
7.need_csc函式
int need_csc(int ifmt, int ofmt)
{
cs_t ics, ocs;
ics = colorspaceofpixel(ifmt);
ocs = colorspaceofpixel(ofmt);
if ((ics == NULL_CS) || (ocs == NULL_CS))
return -1;
else if (ics != ocs)
return 1;
return 0;
}
EXPORT_SYMBOL_GPL(need_csc);
這個函式通過colorspaceofpixel函式分別獲取輸入format和輸出format的顏色空間,如果兩者相同的話,就不需要csc轉化了,如果不同的話就需要csc轉化。這個函式在check_task中呼叫。
8.soc_max_in_width函式
static int soc_max_in_width(u32 is_vdoa)
{
return is_vdoa ? 8192 : 4096;
}
這個函式返回soc最大的寬度,如果傳入的引數為1的話,就返回8192,否則返回4096。這個函式在check_task函式中就是直接這樣用的。引數為1的話代表是vdoa。
9.soc_max_vdi_in_width函式
static int soc_max_vdi_in_width(struct ipu_soc *ipu)
{
int i;
if (!ipu) {
for (i = 0; i < max_ipu_no; i++) {
ipu = ipu_get_soc(i);
if (!IS_ERR_OR_NULL(ipu))
break;
}
if (i == max_ipu_no)
return 720;
}
return IPU_MAX_VDI_IN_WIDTH(ipu->devtype);
}
#define IPU_MAX_VDI_IN_WIDTH(type) ({ (type) >= IPUv3M ? 968 : 720; })
這個函式根據傳入的ipu_soc結構體裡面的devtype來返回vdi的最大寬度。
在ipu_common.c中的ipu_probe函式裡面,以下程式碼是摘取出來的:(在ipu_common.c中詳細分析)
const struct of_device_id *of_id =
of_match_device(imx_ipuv3_dt_ids, &pdev->dev);
const struct ipu_platform_type *iputype = of_id->data;
const struct ipu_devtype *devtype = &iputype->devtype;
ipu = &ipu_array[id];
ipu->devtype = devtype->type;
最終ipu->devtype就呼叫到imx_ipuv3_dt_ids[x]裡面的data資料段:
static const struct of_device_id imx_ipuv3_dt_ids[] = {
{ .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
{ .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
{ .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
{ .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6qp, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_ipuv3_dt_ids);
以ipu_type_imx6qp為例,如下所示:
static struct ipu_platform_type ipu_type_imx6qp = {
<span style="color:#FF0000;">.devtype = {
.name = "IPUv3H",
.cm_ofs = 0x00200000,
.idmac_ofs = 0x00208000,
.ic_ofs = 0x00220000,
.csi0_ofs = 0x00230000,
.csi1_ofs = 0x00238000,
.di0_ofs = 0x00240000,
.di1_ofs = 0x00248000,
.smfc_ofs = 0x00250000,
.dc_ofs = 0x00258000,
.dmfc_ofs = 0x00260000,
.vdi_ofs = 0x00268000,
.cpmem_ofs = 0x00300000,
.srm_ofs = 0x00340000,
.tpm_ofs = 0x00360000,
.dc_tmpl_ofs = 0x00380000,
.type = IPUv3H,
.idmac_used_bufs_present = true,
},</span>
.ch0123_axi = 0,
.ch23_axi = 0,
.ch27_axi = 2,
.ch28_axi = 3,
.normal_axi = 1,
.idmac_used_bufs_en_r = true,
.idmac_used_bufs_en_w = true,
.idmac_used_bufs_max_r = 0x3,
.idmac_used_bufs_max_w = 0x3,
.smfc_idmac_12bit_3planar_bs_fixup = true,
};
這個soc_max_vdi_in_width函式就會比對ipu->devtype即上面標紅的部分,將它於IPUv3M比較,大於就返回968,否則返回720。可以檢視ipu_common.c中可以看出來ipu_type_imx51為"IPUv3EX",ipu_type_imx53為"IPUv3M",ipu_type_imx6q為"IPUv3H",ipu_type_imx6qp為"IPUv3H",所以對於imx51和imx53返回720,imx6q和imx6qp返回968。
這個函式在本檔案中的update_split_setting,check_task,get_res_do_task函式中呼叫。
10.soc_max_in_height函式
static int soc_max_in_height(void)
{
return 4096;
}
11.soc_max_out_width函式
static int soc_max_out_width(void)
{
/* mx51/mx53/mx6q is 1024*/
return 1024;
}
12.soc_max_out_height函式
static int soc_max_out_height(void)
{
/* mx51/mx53/mx6q is 1024*/
return 1024;
}
13.dump_task_info函式
static void dump_task_info(struct ipu_task_entry *t)
{
if (!debug)
return;
dev_dbg(t->dev, "[0x%p]input:\n", (void *)t);
dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->input.format);
dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->input.width);
dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->input.height);
dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->input.crop.w);
dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->input.crop.h);
dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
(void *)t, t->input.crop.pos.x);
dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
(void *)t, t->input.crop.pos.y);
/*列印ipu_task_entry->input的資訊。*/
dev_dbg(t->dev, "[0x%p]input buffer:\n", (void *)t);
dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->input.paddr);
dev_dbg(t->dev, "[0x%p]\ti_off = 0x%x\n", (void *)t, t->set.i_off);
dev_dbg(t->dev, "[0x%p]\ti_uoff = 0x%x\n", (void *)t, t->set.i_uoff);
dev_dbg(t->dev, "[0x%p]\ti_voff = 0x%x\n", (void *)t, t->set.i_voff);
dev_dbg(t->dev, "[0x%p]\tistride = %d\n", (void *)t, t->set.istride);
if (t->input.deinterlace.enable) {
dev_dbg(t->dev, "[0x%p]deinterlace enabled with:\n", (void *)t);
if (t->input.deinterlace.motion != HIGH_MOTION) {
dev_dbg(t->dev, "[0x%p]\tlow/medium motion\n", (void *)t);
dev_dbg(t->dev, "[0x%p]\tpaddr_n = 0x%x\n",
(void *)t, t->input.paddr_n);
} else
dev_dbg(t->dev, "[0x%p]\thigh motion\n", (void *)t);
}
/*列印ipu_task_entry->inputbuffer的一些資訊。*/
dev_dbg(t->dev, "[0x%p]output:\n", (void *)t);
dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->output.format);
dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->output.width);
dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->output.height);
dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->output.crop.w);
dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->output.crop.h);
dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
(void *)t, t->output.crop.pos.x);
dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
(void *)t, t->output.crop.pos.y);
dev_dbg(t->dev, "[0x%p]\trotate = %d\n", (void *)t, t->output.rotate);
/*列印ipu_task_entry->output的資訊。*/
dev_dbg(t->dev, "[0x%p]output buffer:\n", (void *)t);
dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->output.paddr);
dev_dbg(t->dev, "[0x%p]\to_off = 0x%x\n", (void *)t, t->set.o_off);
dev_dbg(t->dev, "[0x%p]\to_uoff = 0x%x\n", (void *)t, t->set.o_uoff);
dev_dbg(t->dev, "[0x%p]\to_voff = 0x%x\n", (void *)t, t->set.o_voff);
dev_dbg(t->dev, "[0x%p]\tostride = %d\n", (void *)t, t->set.ostride);
/*列印ipu_task_entry->outputbuffer的一些資訊。*/
if (t->overlay_en) {
dev_dbg(t->dev, "[0x%p]overlay:\n", (void *)t);
dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n",
(void *)t, t->overlay.format);
dev_dbg(t->dev, "[0x%p]\twidth = %d\n",
(void *)t, t->overlay.width);
dev_dbg(t->dev, "[0x%p]\theight = %d\n",
(void *)t, t->overlay.height);
dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n",
(void *)t, t->overlay.crop.w);
dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n",
(void *)t, t->overlay.crop.h);
dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
(void *)t, t->overlay.crop.pos.x);
dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
(void *)t, t->overlay.crop.pos.y);
/*如果使能了overlay_en的話,列印overlay的一些資訊。*/
dev_dbg(t->dev, "[0x%p]overlay buffer:\n", (void *)t);
dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
(void *)t, t->overlay.paddr);
dev_dbg(t->dev, "[0x%p]\tov_off = 0x%x\n",
(void *)t, t->set.ov_off);
dev_dbg(t->dev, "[0x%p]\tov_uoff = 0x%x\n",
(void *)t, t->set.ov_uoff);
dev_dbg(t->dev, "[0x%p]\tov_voff = 0x%x\n",
(void *)t, t->set.ov_voff);
dev_dbg(t->dev, "[0x%p]\tovstride = %d\n",
(void *)t, t->set.ovstride);
/*列印overlaybuffer的一些資訊。*/
if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
dev_dbg(t->dev, "[0x%p]local alpha enabled with:\n",
(void *)t);
dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
(void *)t, t->overlay.alpha.loc_alp_paddr);
dev_dbg(t->dev, "[0x%p]\tov_alpha_off = 0x%x\n",
(void *)t, t->set.ov_alpha_off);
dev_dbg(t->dev, "[0x%p]\tov_alpha_stride = %d\n",
(void *)t, t->set.ov_alpha_stride);
} else
dev_dbg(t->dev, "[0x%p]globle alpha enabled with value 0x%x\n",
(void *)t, t->overlay.alpha.gvalue);
if (t->overlay.colorkey.enable)
dev_dbg(t->dev, "[0x%p]colorkey enabled with value 0x%x\n",
(void *)t, t->overlay.colorkey.value);
}
/*列印alpha通道的一些資訊。*/
dev_dbg(t->dev, "[0x%p]want task_id = %d\n", (void *)t, t->task_id);
dev_dbg(t->dev, "[0x%p]want task mode is 0x%x\n",
(void *)t, t->set.mode);
dev_dbg(t->dev, "[0x%p]\tIC_MODE = 0x%x\n", (void *)t, IC_MODE);
dev_dbg(t->dev, "[0x%p]\tROT_MODE = 0x%x\n", (void *)t, ROT_MODE);
dev_dbg(t->dev, "[0x%p]\tVDI_MODE = 0x%x\n", (void *)t, VDI_MODE);
dev_dbg(t->dev, "[0x%p]\tTask_no = 0x%x\n\n\n", (void *)t, t->task_no);
}
/*列印這個task的一些資訊。*/
這個函式裡面就是一些列印資訊,可以在合適的地方新增這些列印資訊來輔助除錯。
14.dump_check_err函式
static void dump_check_err(struct device *dev, int err)
{
switch (err) {
case IPU_CHECK_ERR_INPUT_CROP:
dev_err(dev, "input crop setting error\n");
break;
case IPU_CHECK_ERR_OUTPUT_CROP:
dev_err(dev, "output crop setting error\n");
break;
case IPU_CHECK_ERR_OVERLAY_CROP:
dev_err(dev, "overlay crop setting error\n");
break;
case IPU_CHECK_ERR_INPUT_OVER_LIMIT:
dev_err(dev, "input over limitation\n");
break;
case IPU_CHECK_ERR_OVERLAY_WITH_VDI:
dev_err(dev, "do not support overlay with deinterlace\n");
break;
case IPU_CHECK_ERR_OV_OUT_NO_FIT:
dev_err(dev,
"width/height of overlay and ic output should be same\n");
break;
case IPU_CHECK_ERR_PROC_NO_NEED:
dev_err(dev, "no ipu processing need\n");
break;
case IPU_CHECK_ERR_SPLIT_INPUTW_OVER:
dev_err(dev, "split mode input width overflow\n");
break;
case IPU_CHECK_ERR_SPLIT_INPUTH_OVER:
dev_err(dev, "split mode input height overflow\n");
break;
case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER:
dev_err(dev, "split mode output width overflow\n");
break;
case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER:
dev_err(dev, "split mode output height overflow\n");
break;
case IPU_CHECK_ERR_SPLIT_WITH_ROT:
dev_err(dev, "not support split mode with rotation\n");
break;
case IPU_CHECK_ERR_W_DOWNSIZE_OVER:
dev_err(dev, "horizontal downsizing ratio overflow\n");
break;
case IPU_CHECK_ERR_H_DOWNSIZE_OVER:
dev_err(dev, "vertical downsizing ratio overflow\n");
break;
default:
break;
}
}
這個函式在check_task裡面呼叫。在上一個ipu_device.c分析(一)中分析的框架中,
staticstruct file_operations mxc_ipu_fops = { 。。。
.unlocked_ioctl= mxc_ipu_ioctl,
};
在這個mxc_ipu_ioctl函式中,它為應用程式提供了這個IPU_CHECK_TASKioctl巨集,這個巨集的核心是ipu_check_task函式,在這個ipu_check_task函式中呼叫了check_task函式來檢查task是否出錯,這個函式會生成各個錯誤資訊,然後就會呼叫這個dump_check_err函式將錯誤資訊打印出來。同時也會呼叫dump_check_warn函式來列印警告資訊,這個dump_check_warn函式在下面貼出來。
15.dump_check_warn函式
static void dump_check_warn(struct device *dev, int warn)
{
if (warn & IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN)
dev_warn(dev, "input u/v offset not 8 align\n");
if (warn & IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN)
dev_warn(dev, "output u/v offset not 8 align\n");
if (warn & IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN)
dev_warn(dev, "overlay u/v offset not 8 align\n");
}
16.set_crop函式
static int set_crop(struct ipu_crop *crop, int width, int height, int fmt)
{
if ((width == 0) || (height == 0)) {
pr_err("Invalid param: width=%d, height=%d\n", width, height);
return -EINVAL;
}
if ((IPU_PIX_FMT_TILED_NV12 == fmt) ||
(IPU_PIX_FMT_TILED_NV12F == fmt)) {
if (crop->w || crop->h) {
if (((crop->w + crop->pos.x) > width)
|| ((crop->h + crop->pos.y) > height)
|| (0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
|| (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
|| (0 != (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN))
|| (0 != (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN))
) {
pr_err("set_crop error MB align.\n");
return -EINVAL;
}
} else {
crop->pos.x = 0;
crop->pos.y = 0;
crop->w = width;
crop->h = height;
if ((0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
|| (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))) {
pr_err("set_crop error w/h MB align.\n");
return -EINVAL;
}
}
} else {
if (crop->w || crop->h) {
if (((crop->w + crop->pos.x) > (width + 16))
|| ((crop->h + crop->pos.y) > height + 16)) {
pr_err("set_crop error exceeds width/height.\n");
return -EINVAL;
}
} else {
crop->pos.x = 0;
crop->pos.y = 0;
crop->w = width;
crop->h = height;
}
crop->w -= crop->w%8;
crop->h -= crop->h%8;
}
if ((crop->w == 0) || (crop->h == 0)) {
pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n",
crop->w, crop->h);
return -EINVAL;
}
return 0;
}
這個函式根據傳入的width,height和fmt引數設定傳入的structipu_crop*crop引數。它在檔案中主要是用來設定ipu_task_entry結構體中的ipu_output結構體裡面的structipu_crop crop。它在check_task,do_task_vdoa_vdi函式中都有呼叫。
17.update_offset函式
static void update_offset(unsigned int fmt,
unsigned int width, unsigned int height,
unsigned int pos_x, unsigned int pos_y,
int *off, int *uoff, int *voff, int *stride)
{
/* NOTE: u v offset should based on start point of off*/
switch (fmt) {
case IPU_PIX_FMT_YUV420P2:
case IPU_PIX_FMT_YUV420P:
*off = pos_y * width + pos_x;
*uoff = (width * (height - pos_y) - pos_x)
+ (width/2) * (pos_y/2) + pos_x/2;
/* In case height is odd, round up to even */
*voff = *uoff + (width/2) * ((height+1)/2);
break;
case IPU_PIX_FMT_YVU420P:
*off = pos_y * width + pos_x;
*voff = (width * (height - pos_y) - pos_x)
+ (width/2) * (pos_y/2) + pos_x/2;
/* In case height is odd, round up to even */
*uoff = *voff + (width/2) * ((height+1)/2);
break;
case IPU_PIX_FMT_YVU422P:
*off = pos_y * width + po