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