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
13static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {
14	{ V4L2_PIX_FMT_YUV420,  1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV},
15	{ V4L2_PIX_FMT_YVU420,  1, 3, 2, 1, 1, 2, 2, 3, 3, V4L2_FWHT_FL_PIXENC_YUV},
16	{ V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, V4L2_FWHT_FL_PIXENC_YUV},
17	{ V4L2_PIX_FMT_NV12,    1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
18	{ V4L2_PIX_FMT_NV21,    1, 3, 2, 1, 2, 2, 2, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
19	{ V4L2_PIX_FMT_NV16,    1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
20	{ V4L2_PIX_FMT_NV61,    1, 2, 1, 1, 2, 2, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
21	{ V4L2_PIX_FMT_NV24,    1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
22	{ V4L2_PIX_FMT_NV42,    1, 3, 1, 1, 2, 1, 1, 3, 2, V4L2_FWHT_FL_PIXENC_YUV},
23	{ V4L2_PIX_FMT_YUYV,    2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},
24	{ V4L2_PIX_FMT_YVYU,    2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},
25	{ V4L2_PIX_FMT_UYVY,    2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},
26	{ V4L2_PIX_FMT_VYUY,    2, 2, 1, 2, 4, 2, 1, 3, 1, V4L2_FWHT_FL_PIXENC_YUV},
27	{ V4L2_PIX_FMT_BGR24,   3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB},
28	{ V4L2_PIX_FMT_RGB24,   3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_RGB},
29	{ V4L2_PIX_FMT_HSV24,   3, 3, 1, 3, 3, 1, 1, 3, 1, V4L2_FWHT_FL_PIXENC_HSV},
30	{ V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
31	{ V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
32	{ V4L2_PIX_FMT_ABGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
33	{ V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
34	{ V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
35	{ V4L2_PIX_FMT_ARGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
36	{ V4L2_PIX_FMT_BGRX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
37	{ V4L2_PIX_FMT_BGRA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
38	{ V4L2_PIX_FMT_RGBX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
39	{ V4L2_PIX_FMT_RGBA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_RGB},
40	{ V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1, 4, 1, V4L2_FWHT_FL_PIXENC_HSV},
41	{ V4L2_PIX_FMT_GREY,    1, 1, 1, 1, 0, 1, 1, 1, 1, V4L2_FWHT_FL_PIXENC_RGB},
42};
43
44bool 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
56const 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
77const 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
87const 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
94static 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	case V4L2_PIX_FMT_ARGB32:
179		rf->alpha = rf->luma;
180		rf->cr = rf->luma + 1;
181		rf->cb = rf->cr + 2;
182		rf->luma += 2;
183		break;
184	case V4L2_PIX_FMT_BGR32:
185	case V4L2_PIX_FMT_XBGR32:
186	case V4L2_PIX_FMT_ABGR32:
187		rf->cb = rf->luma;
188		rf->cr = rf->cb + 2;
189		rf->luma++;
190		rf->alpha = rf->cr + 1;
191		break;
192	case V4L2_PIX_FMT_BGRX32:
193	case V4L2_PIX_FMT_BGRA32:
194		rf->alpha = rf->luma;
195		rf->cb = rf->luma + 1;
196		rf->cr = rf->cb + 2;
197		rf->luma += 2;
198		break;
199	case V4L2_PIX_FMT_RGBX32:
200	case V4L2_PIX_FMT_RGBA32:
201		rf->alpha = rf->luma + 3;
202		rf->cr = rf->luma;
203		rf->cb = rf->cr + 2;
204		rf->luma++;
205		break;
206	default:
207		return -EINVAL;
208	}
209	return 0;
210}
211
212int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
213{
214	unsigned int size = state->stride * state->coded_height;
215	unsigned int chroma_stride = state->stride;
216	const struct v4l2_fwht_pixfmt_info *info = state->info;
217	struct fwht_cframe_hdr *p_hdr;
218	struct fwht_cframe cf;
219	struct fwht_raw_frame rf;
220	u32 encoding;
221	u32 flags = 0;
222
223	if (!info)
224		return -EINVAL;
225
226	if (prepare_raw_frame(&rf, info, p_in, size))
227		return -EINVAL;
228
229	if (info->planes_num == 3)
230		chroma_stride /= 2;
231
232	if (info->id == V4L2_PIX_FMT_NV24 ||
233	    info->id == V4L2_PIX_FMT_NV42)
234		chroma_stride *= 2;
235
236	cf.i_frame_qp = state->i_frame_qp;
237	cf.p_frame_qp = state->p_frame_qp;
238	cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));
239
240	encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf,
241				     !state->gop_cnt,
242				     state->gop_cnt == state->gop_size - 1,
243				     state->visible_width,
244				     state->visible_height,
245				     state->stride, chroma_stride);
246	if (!(encoding & FWHT_FRAME_PCODED))
247		state->gop_cnt = 0;
248	if (++state->gop_cnt >= state->gop_size)
249		state->gop_cnt = 0;
250
251	p_hdr = (struct fwht_cframe_hdr *)p_out;
252	p_hdr->magic1 = FWHT_MAGIC1;
253	p_hdr->magic2 = FWHT_MAGIC2;
254	p_hdr->version = htonl(V4L2_FWHT_VERSION);
255	p_hdr->width = htonl(state->visible_width);
256	p_hdr->height = htonl(state->visible_height);
257	flags |= (info->components_num - 1) << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET;
258	flags |= info->pixenc;
259	if (encoding & FWHT_LUMA_UNENCODED)
260		flags |= V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED;
261	if (encoding & FWHT_CB_UNENCODED)
262		flags |= V4L2_FWHT_FL_CB_IS_UNCOMPRESSED;
263	if (encoding & FWHT_CR_UNENCODED)
264		flags |= V4L2_FWHT_FL_CR_IS_UNCOMPRESSED;
265	if (encoding & FWHT_ALPHA_UNENCODED)
266		flags |= V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED;
267	if (!(encoding & FWHT_FRAME_PCODED))
268		flags |= V4L2_FWHT_FL_I_FRAME;
269	if (rf.height_div == 1)
270		flags |= V4L2_FWHT_FL_CHROMA_FULL_HEIGHT;
271	if (rf.width_div == 1)
272		flags |= V4L2_FWHT_FL_CHROMA_FULL_WIDTH;
273	p_hdr->flags = htonl(flags);
274	p_hdr->colorspace = htonl(state->colorspace);
275	p_hdr->xfer_func = htonl(state->xfer_func);
276	p_hdr->ycbcr_enc = htonl(state->ycbcr_enc);
277	p_hdr->quantization = htonl(state->quantization);
278	p_hdr->size = htonl(cf.size);
279	return cf.size + sizeof(*p_hdr);
280}
281
282int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
283{
284	u32 flags;
285	struct fwht_cframe cf;
286	unsigned int components_num = 3;
287	unsigned int version;
288	const struct v4l2_fwht_pixfmt_info *info;
289	unsigned int hdr_width_div, hdr_height_div;
290	struct fwht_raw_frame dst_rf;
291	unsigned int dst_chroma_stride = state->stride;
292	unsigned int ref_chroma_stride = state->ref_stride;
293	unsigned int dst_size = state->stride * state->coded_height;
294	unsigned int ref_size;
295
296	if (!state->info)
297		return -EINVAL;
298
299	info = state->info;
300
301	version = ntohl(state->header.version);
302	if (!version || version > V4L2_FWHT_VERSION) {
303		pr_err("version %d is not supported, current version is %d\n",
304		       version, V4L2_FWHT_VERSION);
305		return -EINVAL;
306	}
307
308	if (state->header.magic1 != FWHT_MAGIC1 ||
309	    state->header.magic2 != FWHT_MAGIC2)
310		return -EINVAL;
311
312	/* TODO: support resolution changes */
313	if (ntohl(state->header.width)  != state->visible_width ||
314	    ntohl(state->header.height) != state->visible_height)
315		return -EINVAL;
316
317	flags = ntohl(state->header.flags);
318
319	if (version >= 2) {
320		if ((flags & V4L2_FWHT_FL_PIXENC_MSK) != info->pixenc)
321			return -EINVAL;
322		components_num = 1 + ((flags & V4L2_FWHT_FL_COMPONENTS_NUM_MSK) >>
323				V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
324	}
325
326	if (components_num != info->components_num)
327		return -EINVAL;
328
329	state->colorspace = ntohl(state->header.colorspace);
330	state->xfer_func = ntohl(state->header.xfer_func);
331	state->ycbcr_enc = ntohl(state->header.ycbcr_enc);
332	state->quantization = ntohl(state->header.quantization);
333	cf.rlc_data = (__be16 *)p_in;
334	cf.size = ntohl(state->header.size);
335
336	hdr_width_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
337	hdr_height_div = (flags & V4L2_FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
338	if (hdr_width_div != info->width_div ||
339	    hdr_height_div != info->height_div)
340		return -EINVAL;
341
342	if (prepare_raw_frame(&dst_rf, info, p_out, dst_size))
343		return -EINVAL;
344	if (info->planes_num == 3) {
345		dst_chroma_stride /= 2;
346		ref_chroma_stride /= 2;
347	}
348	if (info->id == V4L2_PIX_FMT_NV24 ||
349	    info->id == V4L2_PIX_FMT_NV42) {
350		dst_chroma_stride *= 2;
351		ref_chroma_stride *= 2;
352	}
353
354
355	ref_size = state->ref_stride * state->coded_height;
356
357	if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf,
358			      ref_size))
359		return -EINVAL;
360
361	if (!fwht_decode_frame(&cf, flags, components_num,
362			state->visible_width, state->visible_height,
363			&state->ref_frame, state->ref_stride, ref_chroma_stride,
364			&dst_rf, state->stride, dst_chroma_stride))
365		return -EINVAL;
366	return 0;
367}
368