1 // SPDX-License-Identifier: LGPL-2.1
3 * A V4L2 frontend for the FWHT codec
5 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
8 #include <linux/errno.h>
9 #include <linux/string.h>
10 #include <linux/videodev2.h>
11 #include "codec-v4l2-fwht.h"
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_RGB32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
33 { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
34 { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
35 { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
36 { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
37 { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB},
40 bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info,
41 u32 width_div, u32 height_div, u32 components_num,
44 if (info->width_div == width_div &&
45 info->height_div == height_div &&
46 (!pixenc || info->pixenc == pixenc) &&
47 info->components_num == components_num)
52 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div,
56 unsigned int start_idx)
60 for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) {
61 bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i],
62 width_div, height_div,
63 components_num, pixenc);
66 return v4l2_fwht_pixfmts + i;
73 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat)
77 for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++)
78 if (v4l2_fwht_pixfmts[i].id == pixelformat)
79 return v4l2_fwht_pixfmts + i;
83 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx)
85 if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts))
87 return v4l2_fwht_pixfmts + idx;
90 static int prepare_raw_frame(struct fwht_raw_frame *rf,
91 const struct v4l2_fwht_pixfmt_info *info, u8 *buf,
95 rf->width_div = info->width_div;
96 rf->height_div = info->height_div;
97 rf->luma_alpha_step = info->luma_alpha_step;
98 rf->chroma_step = info->chroma_step;
100 rf->components_num = info->components_num;
103 * The buffer is NULL if it is the reference
104 * frame of an I-frame in the stateless decoder
114 case V4L2_PIX_FMT_GREY:
118 case V4L2_PIX_FMT_YUV420:
119 rf->cb = rf->luma + size;
120 rf->cr = rf->cb + size / 4;
122 case V4L2_PIX_FMT_YVU420:
123 rf->cr = rf->luma + size;
124 rf->cb = rf->cr + size / 4;
126 case V4L2_PIX_FMT_YUV422P:
127 rf->cb = rf->luma + size;
128 rf->cr = rf->cb + size / 2;
130 case V4L2_PIX_FMT_NV12:
131 case V4L2_PIX_FMT_NV16:
132 case V4L2_PIX_FMT_NV24:
133 rf->cb = rf->luma + size;
136 case V4L2_PIX_FMT_NV21:
137 case V4L2_PIX_FMT_NV61:
138 case V4L2_PIX_FMT_NV42:
139 rf->cr = rf->luma + size;
142 case V4L2_PIX_FMT_YUYV:
143 rf->cb = rf->luma + 1;
146 case V4L2_PIX_FMT_YVYU:
147 rf->cr = rf->luma + 1;
150 case V4L2_PIX_FMT_UYVY:
155 case V4L2_PIX_FMT_VYUY:
160 case V4L2_PIX_FMT_RGB24:
161 case V4L2_PIX_FMT_HSV24:
166 case V4L2_PIX_FMT_BGR24:
171 case V4L2_PIX_FMT_RGB32:
172 case V4L2_PIX_FMT_XRGB32:
173 case V4L2_PIX_FMT_HSV32:
174 rf->cr = rf->luma + 1;
178 case V4L2_PIX_FMT_BGR32:
179 case V4L2_PIX_FMT_XBGR32:
184 case V4L2_PIX_FMT_ARGB32:
185 rf->alpha = rf->luma;
186 rf->cr = rf->luma + 1;
190 case V4L2_PIX_FMT_ABGR32:
194 rf->alpha = rf->cr + 1;
202 int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
204 unsigned int size = state->stride * state->coded_height;
205 unsigned int chroma_stride = state->stride;
206 const struct v4l2_fwht_pixfmt_info *info = state->info;
207 struct fwht_cframe_hdr *p_hdr;
208 struct fwht_cframe cf;
209 struct fwht_raw_frame rf;
216 if (prepare_raw_frame(&rf, info, p_in, size))
219 if (info->planes_num == 3)
222 if (info->id == V4L2_PIX_FMT_NV24 ||
223 info->id == V4L2_PIX_FMT_NV42)
226 cf.i_frame_qp = state->i_frame_qp;
227 cf.p_frame_qp = state->p_frame_qp;
228 cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));
230 encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf,
232 state->gop_cnt == state->gop_size - 1,
233 state->visible_width,
234 state->visible_height,
235 state->stride, chroma_stride);
236 if (!(encoding & FWHT_FRAME_PCODED))
238 if (++state->gop_cnt >= state->gop_size)
241 p_hdr = (struct fwht_cframe_hdr *)p_out;
242 p_hdr->magic1 = FWHT_MAGIC1;
243 p_hdr->magic2 = FWHT_MAGIC2;
244 p_hdr->version = htonl(FWHT_VERSION);
245 p_hdr->width = htonl(state->visible_width);
246 p_hdr->height = htonl(state->visible_height);
247 flags |= (info->components_num - 1) << FWHT_FL_COMPONENTS_NUM_OFFSET;
248 flags |= info->pixenc;
249 if (encoding & FWHT_LUMA_UNENCODED)
250 flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED;
251 if (encoding & FWHT_CB_UNENCODED)
252 flags |= FWHT_FL_CB_IS_UNCOMPRESSED;
253 if (encoding & FWHT_CR_UNENCODED)
254 flags |= FWHT_FL_CR_IS_UNCOMPRESSED;
255 if (encoding & FWHT_ALPHA_UNENCODED)
256 flags |= FWHT_FL_ALPHA_IS_UNCOMPRESSED;
257 if (!(encoding & FWHT_FRAME_PCODED))
258 flags |= FWHT_FL_I_FRAME;
259 if (rf.height_div == 1)
260 flags |= FWHT_FL_CHROMA_FULL_HEIGHT;
261 if (rf.width_div == 1)
262 flags |= FWHT_FL_CHROMA_FULL_WIDTH;
263 p_hdr->flags = htonl(flags);
264 p_hdr->colorspace = htonl(state->colorspace);
265 p_hdr->xfer_func = htonl(state->xfer_func);
266 p_hdr->ycbcr_enc = htonl(state->ycbcr_enc);
267 p_hdr->quantization = htonl(state->quantization);
268 p_hdr->size = htonl(cf.size);
269 return cf.size + sizeof(*p_hdr);
272 int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
275 struct fwht_cframe cf;
276 unsigned int components_num = 3;
277 unsigned int version;
278 const struct v4l2_fwht_pixfmt_info *info;
279 unsigned int hdr_width_div, hdr_height_div;
280 struct fwht_raw_frame dst_rf;
281 unsigned int dst_chroma_stride = state->stride;
282 unsigned int ref_chroma_stride = state->ref_stride;
283 unsigned int dst_size = state->stride * state->coded_height;
284 unsigned int ref_size;
291 version = ntohl(state->header.version);
292 if (!version || version > FWHT_VERSION) {
293 pr_err("version %d is not supported, current version is %d\n",
294 version, FWHT_VERSION);
298 if (state->header.magic1 != FWHT_MAGIC1 ||
299 state->header.magic2 != FWHT_MAGIC2)
302 /* TODO: support resolution changes */
303 if (ntohl(state->header.width) != state->visible_width ||
304 ntohl(state->header.height) != state->visible_height)
307 flags = ntohl(state->header.flags);
310 if ((flags & FWHT_FL_PIXENC_MSK) != info->pixenc)
312 components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
313 FWHT_FL_COMPONENTS_NUM_OFFSET);
316 if (components_num != info->components_num)
319 state->colorspace = ntohl(state->header.colorspace);
320 state->xfer_func = ntohl(state->header.xfer_func);
321 state->ycbcr_enc = ntohl(state->header.ycbcr_enc);
322 state->quantization = ntohl(state->header.quantization);
323 cf.rlc_data = (__be16 *)p_in;
324 cf.size = ntohl(state->header.size);
326 hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
327 hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
328 if (hdr_width_div != info->width_div ||
329 hdr_height_div != info->height_div)
332 if (prepare_raw_frame(&dst_rf, info, p_out, dst_size))
334 if (info->planes_num == 3) {
335 dst_chroma_stride /= 2;
336 ref_chroma_stride /= 2;
338 if (info->id == V4L2_PIX_FMT_NV24 ||
339 info->id == V4L2_PIX_FMT_NV42) {
340 dst_chroma_stride *= 2;
341 ref_chroma_stride *= 2;
345 ref_size = state->ref_stride * state->coded_height;
347 if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf,
351 if (!fwht_decode_frame(&cf, flags, components_num,
352 state->visible_width, state->visible_height,
353 &state->ref_frame, state->ref_stride, ref_chroma_stride,
354 &dst_rf, state->stride, dst_chroma_stride))