xref: /OK3568_Linux_fs/kernel/drivers/media/test-drivers/vicodec/codec-v4l2-fwht.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: LGPL-2.1
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * A V4L2 frontend for the FWHT codec
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/errno.h>
9*4882a593Smuzhiyun #include <linux/string.h>
10*4882a593Smuzhiyun #include <linux/videodev2.h>
11*4882a593Smuzhiyun #include "codec-v4l2-fwht.h"
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {
14*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_YUV420,  1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV},
15*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_YVU420,  1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV},
16*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, FWHT_FL_PIXENC_YUV},
17*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_NV12,    1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV},
18*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_NV21,    1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV},
19*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_NV16,    1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV},
20*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_NV61,    1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV},
21*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_NV24,    1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV},
22*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_NV42,    1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV},
23*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_YUYV,    2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV},
24*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_YVYU,    2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV},
25*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_UYVY,    2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV},
26*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_VYUY,    2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV},
27*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_BGR24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
28*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_RGB24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
29*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_HSV24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
30*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
31*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
32*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_ABGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
33*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
34*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
35*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_ARGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
36*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_BGRX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
37*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_BGRA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
38*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_RGBX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
39*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_RGBA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
40*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_HSV},
41*4882a593Smuzhiyun 	{ V4L2_PIX_FMT_GREY,    1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB},
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info * info,u32 width_div,u32 height_div,u32 components_num,u32 pixenc)44*4882a593Smuzhiyun bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info,
45*4882a593Smuzhiyun 			    u32 width_div, u32 height_div, u32 components_num,
46*4882a593Smuzhiyun 			    u32 pixenc)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	if (info->width_div == width_div &&
49*4882a593Smuzhiyun 	    info->height_div == height_div &&
50*4882a593Smuzhiyun 	    (!pixenc || info->pixenc == pixenc) &&
51*4882a593Smuzhiyun 	    info->components_num == components_num)
52*4882a593Smuzhiyun 		return true;
53*4882a593Smuzhiyun 	return false;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
v4l2_fwht_find_nth_fmt(u32 width_div,u32 height_div,u32 components_num,u32 pixenc,unsigned int start_idx)56*4882a593Smuzhiyun const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div,
57*4882a593Smuzhiyun 							  u32 height_div,
58*4882a593Smuzhiyun 							  u32 components_num,
59*4882a593Smuzhiyun 							  u32 pixenc,
60*4882a593Smuzhiyun 							  unsigned int start_idx)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	unsigned int i;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) {
65*4882a593Smuzhiyun 		bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i],
66*4882a593Smuzhiyun 						       width_div, height_div,
67*4882a593Smuzhiyun 						       components_num, pixenc);
68*4882a593Smuzhiyun 		if (is_valid) {
69*4882a593Smuzhiyun 			if (start_idx == 0)
70*4882a593Smuzhiyun 				return v4l2_fwht_pixfmts + i;
71*4882a593Smuzhiyun 			start_idx--;
72*4882a593Smuzhiyun 		}
73*4882a593Smuzhiyun 	}
74*4882a593Smuzhiyun 	return NULL;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
v4l2_fwht_find_pixfmt(u32 pixelformat)77*4882a593Smuzhiyun const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	unsigned int i;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++)
82*4882a593Smuzhiyun 		if (v4l2_fwht_pixfmts[i].id == pixelformat)
83*4882a593Smuzhiyun 			return v4l2_fwht_pixfmts + i;
84*4882a593Smuzhiyun 	return NULL;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
v4l2_fwht_get_pixfmt(u32 idx)87*4882a593Smuzhiyun const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts))
90*4882a593Smuzhiyun 		return NULL;
91*4882a593Smuzhiyun 	return v4l2_fwht_pixfmts + idx;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
prepare_raw_frame(struct fwht_raw_frame * rf,const struct v4l2_fwht_pixfmt_info * info,u8 * buf,unsigned int size)94*4882a593Smuzhiyun static int prepare_raw_frame(struct fwht_raw_frame *rf,
95*4882a593Smuzhiyun 			 const struct v4l2_fwht_pixfmt_info *info, u8 *buf,
96*4882a593Smuzhiyun 			 unsigned int size)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	rf->luma = buf;
99*4882a593Smuzhiyun 	rf->width_div = info->width_div;
100*4882a593Smuzhiyun 	rf->height_div = info->height_div;
101*4882a593Smuzhiyun 	rf->luma_alpha_step = info->luma_alpha_step;
102*4882a593Smuzhiyun 	rf->chroma_step = info->chroma_step;
103*4882a593Smuzhiyun 	rf->alpha = NULL;
104*4882a593Smuzhiyun 	rf->components_num = info->components_num;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	/*
107*4882a593Smuzhiyun 	 * The buffer is NULL if it is the reference
108*4882a593Smuzhiyun 	 * frame of an I-frame in the stateless decoder
109*4882a593Smuzhiyun 	 */
110*4882a593Smuzhiyun 	if (!buf) {
111*4882a593Smuzhiyun 		rf->luma = NULL;
112*4882a593Smuzhiyun 		rf->cb = NULL;
113*4882a593Smuzhiyun 		rf->cr = NULL;
114*4882a593Smuzhiyun 		rf->alpha = NULL;
115*4882a593Smuzhiyun 		return 0;
116*4882a593Smuzhiyun 	}
117*4882a593Smuzhiyun 	switch (info->id) {
118*4882a593Smuzhiyun 	case V4L2_PIX_FMT_GREY:
119*4882a593Smuzhiyun 		rf->cb = NULL;
120*4882a593Smuzhiyun 		rf->cr = NULL;
121*4882a593Smuzhiyun 		break;
122*4882a593Smuzhiyun 	case V4L2_PIX_FMT_YUV420:
123*4882a593Smuzhiyun 		rf->cb = rf->luma + size;
124*4882a593Smuzhiyun 		rf->cr = rf->cb + size / 4;
125*4882a593Smuzhiyun 		break;
126*4882a593Smuzhiyun 	case V4L2_PIX_FMT_YVU420:
127*4882a593Smuzhiyun 		rf->cr = rf->luma + size;
128*4882a593Smuzhiyun 		rf->cb = rf->cr + size / 4;
129*4882a593Smuzhiyun 		break;
130*4882a593Smuzhiyun 	case V4L2_PIX_FMT_YUV422P:
131*4882a593Smuzhiyun 		rf->cb = rf->luma + size;
132*4882a593Smuzhiyun 		rf->cr = rf->cb + size / 2;
133*4882a593Smuzhiyun 		break;
134*4882a593Smuzhiyun 	case V4L2_PIX_FMT_NV12:
135*4882a593Smuzhiyun 	case V4L2_PIX_FMT_NV16:
136*4882a593Smuzhiyun 	case V4L2_PIX_FMT_NV24:
137*4882a593Smuzhiyun 		rf->cb = rf->luma + size;
138*4882a593Smuzhiyun 		rf->cr = rf->cb + 1;
139*4882a593Smuzhiyun 		break;
140*4882a593Smuzhiyun 	case V4L2_PIX_FMT_NV21:
141*4882a593Smuzhiyun 	case V4L2_PIX_FMT_NV61:
142*4882a593Smuzhiyun 	case V4L2_PIX_FMT_NV42:
143*4882a593Smuzhiyun 		rf->cr = rf->luma + size;
144*4882a593Smuzhiyun 		rf->cb = rf->cr + 1;
145*4882a593Smuzhiyun 		break;
146*4882a593Smuzhiyun 	case V4L2_PIX_FMT_YUYV:
147*4882a593Smuzhiyun 		rf->cb = rf->luma + 1;
148*4882a593Smuzhiyun 		rf->cr = rf->cb + 2;
149*4882a593Smuzhiyun 		break;
150*4882a593Smuzhiyun 	case V4L2_PIX_FMT_YVYU:
151*4882a593Smuzhiyun 		rf->cr = rf->luma + 1;
152*4882a593Smuzhiyun 		rf->cb = rf->cr + 2;
153*4882a593Smuzhiyun 		break;
154*4882a593Smuzhiyun 	case V4L2_PIX_FMT_UYVY:
155*4882a593Smuzhiyun 		rf->cb = rf->luma;
156*4882a593Smuzhiyun 		rf->cr = rf->cb + 2;
157*4882a593Smuzhiyun 		rf->luma++;
158*4882a593Smuzhiyun 		break;
159*4882a593Smuzhiyun 	case V4L2_PIX_FMT_VYUY:
160*4882a593Smuzhiyun 		rf->cr = rf->luma;
161*4882a593Smuzhiyun 		rf->cb = rf->cr + 2;
162*4882a593Smuzhiyun 		rf->luma++;
163*4882a593Smuzhiyun 		break;
164*4882a593Smuzhiyun 	case V4L2_PIX_FMT_RGB24:
165*4882a593Smuzhiyun 	case V4L2_PIX_FMT_HSV24:
166*4882a593Smuzhiyun 		rf->cr = rf->luma;
167*4882a593Smuzhiyun 		rf->cb = rf->cr + 2;
168*4882a593Smuzhiyun 		rf->luma++;
169*4882a593Smuzhiyun 		break;
170*4882a593Smuzhiyun 	case V4L2_PIX_FMT_BGR24:
171*4882a593Smuzhiyun 		rf->cb = rf->luma;
172*4882a593Smuzhiyun 		rf->cr = rf->cb + 2;
173*4882a593Smuzhiyun 		rf->luma++;
174*4882a593Smuzhiyun 		break;
175*4882a593Smuzhiyun 	case V4L2_PIX_FMT_RGB32:
176*4882a593Smuzhiyun 	case V4L2_PIX_FMT_XRGB32:
177*4882a593Smuzhiyun 	case V4L2_PIX_FMT_HSV32:
178*4882a593Smuzhiyun 	case V4L2_PIX_FMT_ARGB32:
179*4882a593Smuzhiyun 		rf->alpha = rf->luma;
180*4882a593Smuzhiyun 		rf->cr = rf->luma + 1;
181*4882a593Smuzhiyun 		rf->cb = rf->cr + 2;
182*4882a593Smuzhiyun 		rf->luma += 2;
183*4882a593Smuzhiyun 		break;
184*4882a593Smuzhiyun 	case V4L2_PIX_FMT_BGR32:
185*4882a593Smuzhiyun 	case V4L2_PIX_FMT_XBGR32:
186*4882a593Smuzhiyun 	case V4L2_PIX_FMT_ABGR32:
187*4882a593Smuzhiyun 		rf->cb = rf->luma;
188*4882a593Smuzhiyun 		rf->cr = rf->cb + 2;
189*4882a593Smuzhiyun 		rf->luma++;
190*4882a593Smuzhiyun 		rf->alpha = rf->cr + 1;
191*4882a593Smuzhiyun 		break;
192*4882a593Smuzhiyun 	case V4L2_PIX_FMT_BGRX32:
193*4882a593Smuzhiyun 	case V4L2_PIX_FMT_BGRA32:
194*4882a593Smuzhiyun 		rf->alpha = rf->luma;
195*4882a593Smuzhiyun 		rf->cb = rf->luma + 1;
196*4882a593Smuzhiyun 		rf->cr = rf->cb + 2;
197*4882a593Smuzhiyun 		rf->luma += 2;
198*4882a593Smuzhiyun 		break;
199*4882a593Smuzhiyun 	case V4L2_PIX_FMT_RGBX32:
200*4882a593Smuzhiyun 	case V4L2_PIX_FMT_RGBA32:
201*4882a593Smuzhiyun 		rf->alpha = rf->luma + 3;
202*4882a593Smuzhiyun 		rf->cr = rf->luma;
203*4882a593Smuzhiyun 		rf->cb = rf->cr + 2;
204*4882a593Smuzhiyun 		rf->luma++;
205*4882a593Smuzhiyun 		break;
206*4882a593Smuzhiyun 	default:
207*4882a593Smuzhiyun 		return -EINVAL;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 	return 0;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
v4l2_fwht_encode(struct v4l2_fwht_state * state,u8 * p_in,u8 * p_out)212*4882a593Smuzhiyun int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	unsigned int size = state->stride * state->coded_height;
215*4882a593Smuzhiyun 	unsigned int chroma_stride = state->stride;
216*4882a593Smuzhiyun 	const struct v4l2_fwht_pixfmt_info *info = state->info;
217*4882a593Smuzhiyun 	struct fwht_cframe_hdr *p_hdr;
218*4882a593Smuzhiyun 	struct fwht_cframe cf;
219*4882a593Smuzhiyun 	struct fwht_raw_frame rf;
220*4882a593Smuzhiyun 	u32 encoding;
221*4882a593Smuzhiyun 	u32 flags = 0;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	if (!info)
224*4882a593Smuzhiyun 		return -EINVAL;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if (prepare_raw_frame(&rf, info, p_in, size))
227*4882a593Smuzhiyun 		return -EINVAL;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	if (info->planes_num == 3)
230*4882a593Smuzhiyun 		chroma_stride /= 2;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	if (info->id == V4L2_PIX_FMT_NV24 ||
233*4882a593Smuzhiyun 	    info->id == V4L2_PIX_FMT_NV42)
234*4882a593Smuzhiyun 		chroma_stride *= 2;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	cf.i_frame_qp = state->i_frame_qp;
237*4882a593Smuzhiyun 	cf.p_frame_qp = state->p_frame_qp;
238*4882a593Smuzhiyun 	cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf,
241*4882a593Smuzhiyun 				     !state->gop_cnt,
242*4882a593Smuzhiyun 				     state->gop_cnt == state->gop_size - 1,
243*4882a593Smuzhiyun 				     state->visible_width,
244*4882a593Smuzhiyun 				     state->visible_height,
245*4882a593Smuzhiyun 				     state->stride, chroma_stride);
246*4882a593Smuzhiyun 	if (!(encoding & FWHT_FRAME_PCODED))
247*4882a593Smuzhiyun 		state->gop_cnt = 0;
248*4882a593Smuzhiyun 	if (++state->gop_cnt >= state->gop_size)
249*4882a593Smuzhiyun 		state->gop_cnt = 0;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	p_hdr = (struct fwht_cframe_hdr *)p_out;
252*4882a593Smuzhiyun 	p_hdr->magic1 = FWHT_MAGIC1;
253*4882a593Smuzhiyun 	p_hdr->magic2 = FWHT_MAGIC2;
254*4882a593Smuzhiyun 	p_hdr->version = htonl(FWHT_VERSION);
255*4882a593Smuzhiyun 	p_hdr->width = htonl(state->visible_width);
256*4882a593Smuzhiyun 	p_hdr->height = htonl(state->visible_height);
257*4882a593Smuzhiyun 	flags |= (info->components_num - 1) << FWHT_FL_COMPONENTS_NUM_OFFSET;
258*4882a593Smuzhiyun 	flags |= info->pixenc;
259*4882a593Smuzhiyun 	if (encoding & FWHT_LUMA_UNENCODED)
260*4882a593Smuzhiyun 		flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED;
261*4882a593Smuzhiyun 	if (encoding & FWHT_CB_UNENCODED)
262*4882a593Smuzhiyun 		flags |= FWHT_FL_CB_IS_UNCOMPRESSED;
263*4882a593Smuzhiyun 	if (encoding & FWHT_CR_UNENCODED)
264*4882a593Smuzhiyun 		flags |= FWHT_FL_CR_IS_UNCOMPRESSED;
265*4882a593Smuzhiyun 	if (encoding & FWHT_ALPHA_UNENCODED)
266*4882a593Smuzhiyun 		flags |= FWHT_FL_ALPHA_IS_UNCOMPRESSED;
267*4882a593Smuzhiyun 	if (!(encoding & FWHT_FRAME_PCODED))
268*4882a593Smuzhiyun 		flags |= FWHT_FL_I_FRAME;
269*4882a593Smuzhiyun 	if (rf.height_div == 1)
270*4882a593Smuzhiyun 		flags |= FWHT_FL_CHROMA_FULL_HEIGHT;
271*4882a593Smuzhiyun 	if (rf.width_div == 1)
272*4882a593Smuzhiyun 		flags |= FWHT_FL_CHROMA_FULL_WIDTH;
273*4882a593Smuzhiyun 	p_hdr->flags = htonl(flags);
274*4882a593Smuzhiyun 	p_hdr->colorspace = htonl(state->colorspace);
275*4882a593Smuzhiyun 	p_hdr->xfer_func = htonl(state->xfer_func);
276*4882a593Smuzhiyun 	p_hdr->ycbcr_enc = htonl(state->ycbcr_enc);
277*4882a593Smuzhiyun 	p_hdr->quantization = htonl(state->quantization);
278*4882a593Smuzhiyun 	p_hdr->size = htonl(cf.size);
279*4882a593Smuzhiyun 	return cf.size + sizeof(*p_hdr);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
v4l2_fwht_decode(struct v4l2_fwht_state * state,u8 * p_in,u8 * p_out)282*4882a593Smuzhiyun int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	u32 flags;
285*4882a593Smuzhiyun 	struct fwht_cframe cf;
286*4882a593Smuzhiyun 	unsigned int components_num = 3;
287*4882a593Smuzhiyun 	unsigned int version;
288*4882a593Smuzhiyun 	const struct v4l2_fwht_pixfmt_info *info;
289*4882a593Smuzhiyun 	unsigned int hdr_width_div, hdr_height_div;
290*4882a593Smuzhiyun 	struct fwht_raw_frame dst_rf;
291*4882a593Smuzhiyun 	unsigned int dst_chroma_stride = state->stride;
292*4882a593Smuzhiyun 	unsigned int ref_chroma_stride = state->ref_stride;
293*4882a593Smuzhiyun 	unsigned int dst_size = state->stride * state->coded_height;
294*4882a593Smuzhiyun 	unsigned int ref_size;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	if (!state->info)
297*4882a593Smuzhiyun 		return -EINVAL;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	info = state->info;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	version = ntohl(state->header.version);
302*4882a593Smuzhiyun 	if (!version || version > FWHT_VERSION) {
303*4882a593Smuzhiyun 		pr_err("version %d is not supported, current version is %d\n",
304*4882a593Smuzhiyun 		       version, FWHT_VERSION);
305*4882a593Smuzhiyun 		return -EINVAL;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (state->header.magic1 != FWHT_MAGIC1 ||
309*4882a593Smuzhiyun 	    state->header.magic2 != FWHT_MAGIC2)
310*4882a593Smuzhiyun 		return -EINVAL;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	/* TODO: support resolution changes */
313*4882a593Smuzhiyun 	if (ntohl(state->header.width)  != state->visible_width ||
314*4882a593Smuzhiyun 	    ntohl(state->header.height) != state->visible_height)
315*4882a593Smuzhiyun 		return -EINVAL;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	flags = ntohl(state->header.flags);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	if (version >= 2) {
320*4882a593Smuzhiyun 		if ((flags & FWHT_FL_PIXENC_MSK) != info->pixenc)
321*4882a593Smuzhiyun 			return -EINVAL;
322*4882a593Smuzhiyun 		components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
323*4882a593Smuzhiyun 				FWHT_FL_COMPONENTS_NUM_OFFSET);
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	if (components_num != info->components_num)
327*4882a593Smuzhiyun 		return -EINVAL;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	state->colorspace = ntohl(state->header.colorspace);
330*4882a593Smuzhiyun 	state->xfer_func = ntohl(state->header.xfer_func);
331*4882a593Smuzhiyun 	state->ycbcr_enc = ntohl(state->header.ycbcr_enc);
332*4882a593Smuzhiyun 	state->quantization = ntohl(state->header.quantization);
333*4882a593Smuzhiyun 	cf.rlc_data = (__be16 *)p_in;
334*4882a593Smuzhiyun 	cf.size = ntohl(state->header.size);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
337*4882a593Smuzhiyun 	hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
338*4882a593Smuzhiyun 	if (hdr_width_div != info->width_div ||
339*4882a593Smuzhiyun 	    hdr_height_div != info->height_div)
340*4882a593Smuzhiyun 		return -EINVAL;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	if (prepare_raw_frame(&dst_rf, info, p_out, dst_size))
343*4882a593Smuzhiyun 		return -EINVAL;
344*4882a593Smuzhiyun 	if (info->planes_num == 3) {
345*4882a593Smuzhiyun 		dst_chroma_stride /= 2;
346*4882a593Smuzhiyun 		ref_chroma_stride /= 2;
347*4882a593Smuzhiyun 	}
348*4882a593Smuzhiyun 	if (info->id == V4L2_PIX_FMT_NV24 ||
349*4882a593Smuzhiyun 	    info->id == V4L2_PIX_FMT_NV42) {
350*4882a593Smuzhiyun 		dst_chroma_stride *= 2;
351*4882a593Smuzhiyun 		ref_chroma_stride *= 2;
352*4882a593Smuzhiyun 	}
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	ref_size = state->ref_stride * state->coded_height;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf,
358*4882a593Smuzhiyun 			      ref_size))
359*4882a593Smuzhiyun 		return -EINVAL;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	if (!fwht_decode_frame(&cf, flags, components_num,
362*4882a593Smuzhiyun 			state->visible_width, state->visible_height,
363*4882a593Smuzhiyun 			&state->ref_frame, state->ref_stride, ref_chroma_stride,
364*4882a593Smuzhiyun 			&dst_rf, state->stride, dst_chroma_stride))
365*4882a593Smuzhiyun 		return -EINVAL;
366*4882a593Smuzhiyun 	return 0;
367*4882a593Smuzhiyun }
368