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_GREY, 1, 1, 1, 1, 0, 1, 1, 1},
15 { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3},
16 { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3},
17 { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3},
18 { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3},
19 { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3},
20 { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3},
21 { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3},
22 { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3},
23 { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3},
24 { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3},
25 { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3},
26 { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3},
27 { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3},
28 { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3},
29 { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3},
30 { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3},
31 { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 3},
32 { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 3},
33 { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 3},
34 { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 3},
35 { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 3},
36 { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4},
37 { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4},
41 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat)
45 for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++)
46 if (v4l2_fwht_pixfmts[i].id == pixelformat)
47 return v4l2_fwht_pixfmts + i;
51 const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx)
53 if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts))
55 return v4l2_fwht_pixfmts + idx;
58 int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
60 unsigned int size = state->width * state->height;
61 const struct v4l2_fwht_pixfmt_info *info = state->info;
62 struct fwht_cframe_hdr *p_hdr;
63 struct fwht_cframe cf;
64 struct fwht_raw_frame rf;
70 rf.width = state->width;
71 rf.height = state->height;
73 rf.width_div = info->width_div;
74 rf.height_div = info->height_div;
75 rf.luma_alpha_step = info->luma_alpha_step;
76 rf.chroma_step = info->chroma_step;
78 rf.components_num = info->components_num;
81 case V4L2_PIX_FMT_GREY:
85 case V4L2_PIX_FMT_YUV420:
86 rf.cb = rf.luma + size;
87 rf.cr = rf.cb + size / 4;
89 case V4L2_PIX_FMT_YVU420:
90 rf.cr = rf.luma + size;
91 rf.cb = rf.cr + size / 4;
93 case V4L2_PIX_FMT_YUV422P:
94 rf.cb = rf.luma + size;
95 rf.cr = rf.cb + size / 2;
97 case V4L2_PIX_FMT_NV12:
98 case V4L2_PIX_FMT_NV16:
99 case V4L2_PIX_FMT_NV24:
100 rf.cb = rf.luma + size;
103 case V4L2_PIX_FMT_NV21:
104 case V4L2_PIX_FMT_NV61:
105 case V4L2_PIX_FMT_NV42:
106 rf.cr = rf.luma + size;
109 case V4L2_PIX_FMT_YUYV:
113 case V4L2_PIX_FMT_YVYU:
117 case V4L2_PIX_FMT_UYVY:
122 case V4L2_PIX_FMT_VYUY:
127 case V4L2_PIX_FMT_RGB24:
128 case V4L2_PIX_FMT_HSV24:
133 case V4L2_PIX_FMT_BGR24:
138 case V4L2_PIX_FMT_RGB32:
139 case V4L2_PIX_FMT_XRGB32:
140 case V4L2_PIX_FMT_HSV32:
145 case V4L2_PIX_FMT_BGR32:
146 case V4L2_PIX_FMT_XBGR32:
151 case V4L2_PIX_FMT_ARGB32:
157 case V4L2_PIX_FMT_ABGR32:
161 rf.alpha = rf.cr + 1;
167 cf.width = state->width;
168 cf.height = state->height;
169 cf.i_frame_qp = state->i_frame_qp;
170 cf.p_frame_qp = state->p_frame_qp;
171 cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr));
173 encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf,
175 state->gop_cnt == state->gop_size - 1);
176 if (!(encoding & FWHT_FRAME_PCODED))
178 if (++state->gop_cnt >= state->gop_size)
181 p_hdr = (struct fwht_cframe_hdr *)p_out;
182 p_hdr->magic1 = FWHT_MAGIC1;
183 p_hdr->magic2 = FWHT_MAGIC2;
184 p_hdr->version = htonl(FWHT_VERSION);
185 p_hdr->width = htonl(cf.width);
186 p_hdr->height = htonl(cf.height);
187 flags |= (info->components_num - 1) << FWHT_FL_COMPONENTS_NUM_OFFSET;
188 if (encoding & FWHT_LUMA_UNENCODED)
189 flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED;
190 if (encoding & FWHT_CB_UNENCODED)
191 flags |= FWHT_FL_CB_IS_UNCOMPRESSED;
192 if (encoding & FWHT_CR_UNENCODED)
193 flags |= FWHT_FL_CR_IS_UNCOMPRESSED;
194 if (encoding & FWHT_ALPHA_UNENCODED)
195 flags |= FWHT_FL_ALPHA_IS_UNCOMPRESSED;
196 if (rf.height_div == 1)
197 flags |= FWHT_FL_CHROMA_FULL_HEIGHT;
198 if (rf.width_div == 1)
199 flags |= FWHT_FL_CHROMA_FULL_WIDTH;
200 p_hdr->flags = htonl(flags);
201 p_hdr->colorspace = htonl(state->colorspace);
202 p_hdr->xfer_func = htonl(state->xfer_func);
203 p_hdr->ycbcr_enc = htonl(state->ycbcr_enc);
204 p_hdr->quantization = htonl(state->quantization);
205 p_hdr->size = htonl(cf.size);
206 state->ref_frame.width = cf.width;
207 state->ref_frame.height = cf.height;
208 return cf.size + sizeof(*p_hdr);
211 int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
213 unsigned int size = state->width * state->height;
214 unsigned int chroma_size = size;
217 struct fwht_cframe_hdr *p_hdr;
218 struct fwht_cframe cf;
220 unsigned int components_num = 3;
221 unsigned int version;
226 p_hdr = (struct fwht_cframe_hdr *)p_in;
227 cf.width = ntohl(p_hdr->width);
228 cf.height = ntohl(p_hdr->height);
230 version = ntohl(p_hdr->version);
231 if (!version || version > FWHT_VERSION) {
232 pr_err("version %d is not supported, current version is %d\n",
233 version, FWHT_VERSION);
237 if (p_hdr->magic1 != FWHT_MAGIC1 ||
238 p_hdr->magic2 != FWHT_MAGIC2 ||
239 (cf.width & 7) || (cf.height & 7))
242 /* TODO: support resolution changes */
243 if (cf.width != state->width || cf.height != state->height)
246 flags = ntohl(p_hdr->flags);
248 if (version == FWHT_VERSION) {
249 components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
250 FWHT_FL_COMPONENTS_NUM_OFFSET);
253 state->colorspace = ntohl(p_hdr->colorspace);
254 state->xfer_func = ntohl(p_hdr->xfer_func);
255 state->ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
256 state->quantization = ntohl(p_hdr->quantization);
257 cf.rlc_data = (__be16 *)(p_in + sizeof(*p_hdr));
259 if (!(flags & FWHT_FL_CHROMA_FULL_WIDTH))
261 if (!(flags & FWHT_FL_CHROMA_FULL_HEIGHT))
264 fwht_decode_frame(&cf, &state->ref_frame, flags, components_num);
267 * TODO - handle the case where the compressed stream encodes a
268 * different format than the requested decoded format.
270 switch (state->info->id) {
271 case V4L2_PIX_FMT_GREY:
272 memcpy(p_out, state->ref_frame.luma, size);
274 case V4L2_PIX_FMT_YUV420:
275 case V4L2_PIX_FMT_YUV422P:
276 memcpy(p_out, state->ref_frame.luma, size);
278 memcpy(p_out, state->ref_frame.cb, chroma_size);
279 p_out += chroma_size;
280 memcpy(p_out, state->ref_frame.cr, chroma_size);
282 case V4L2_PIX_FMT_YVU420:
283 memcpy(p_out, state->ref_frame.luma, size);
285 memcpy(p_out, state->ref_frame.cr, chroma_size);
286 p_out += chroma_size;
287 memcpy(p_out, state->ref_frame.cb, chroma_size);
289 case V4L2_PIX_FMT_NV12:
290 case V4L2_PIX_FMT_NV16:
291 case V4L2_PIX_FMT_NV24:
292 memcpy(p_out, state->ref_frame.luma, size);
294 for (i = 0, p = p_out; i < chroma_size; i++) {
295 *p++ = state->ref_frame.cb[i];
296 *p++ = state->ref_frame.cr[i];
299 case V4L2_PIX_FMT_NV21:
300 case V4L2_PIX_FMT_NV61:
301 case V4L2_PIX_FMT_NV42:
302 memcpy(p_out, state->ref_frame.luma, size);
304 for (i = 0, p = p_out; i < chroma_size; i++) {
305 *p++ = state->ref_frame.cr[i];
306 *p++ = state->ref_frame.cb[i];
309 case V4L2_PIX_FMT_YUYV:
310 for (i = 0, p = p_out; i < size; i += 2) {
311 *p++ = state->ref_frame.luma[i];
312 *p++ = state->ref_frame.cb[i / 2];
313 *p++ = state->ref_frame.luma[i + 1];
314 *p++ = state->ref_frame.cr[i / 2];
317 case V4L2_PIX_FMT_YVYU:
318 for (i = 0, p = p_out; i < size; i += 2) {
319 *p++ = state->ref_frame.luma[i];
320 *p++ = state->ref_frame.cr[i / 2];
321 *p++ = state->ref_frame.luma[i + 1];
322 *p++ = state->ref_frame.cb[i / 2];
325 case V4L2_PIX_FMT_UYVY:
326 for (i = 0, p = p_out; i < size; i += 2) {
327 *p++ = state->ref_frame.cb[i / 2];
328 *p++ = state->ref_frame.luma[i];
329 *p++ = state->ref_frame.cr[i / 2];
330 *p++ = state->ref_frame.luma[i + 1];
333 case V4L2_PIX_FMT_VYUY:
334 for (i = 0, p = p_out; i < size; i += 2) {
335 *p++ = state->ref_frame.cr[i / 2];
336 *p++ = state->ref_frame.luma[i];
337 *p++ = state->ref_frame.cb[i / 2];
338 *p++ = state->ref_frame.luma[i + 1];
341 case V4L2_PIX_FMT_RGB24:
342 case V4L2_PIX_FMT_HSV24:
343 for (i = 0, p = p_out; i < size; i++) {
344 *p++ = state->ref_frame.cr[i];
345 *p++ = state->ref_frame.luma[i];
346 *p++ = state->ref_frame.cb[i];
349 case V4L2_PIX_FMT_BGR24:
350 for (i = 0, p = p_out; i < size; i++) {
351 *p++ = state->ref_frame.cb[i];
352 *p++ = state->ref_frame.luma[i];
353 *p++ = state->ref_frame.cr[i];
356 case V4L2_PIX_FMT_RGB32:
357 case V4L2_PIX_FMT_XRGB32:
358 case V4L2_PIX_FMT_HSV32:
359 for (i = 0, p = p_out; i < size; i++) {
361 *p++ = state->ref_frame.cr[i];
362 *p++ = state->ref_frame.luma[i];
363 *p++ = state->ref_frame.cb[i];
366 case V4L2_PIX_FMT_BGR32:
367 case V4L2_PIX_FMT_XBGR32:
368 for (i = 0, p = p_out; i < size; i++) {
369 *p++ = state->ref_frame.cb[i];
370 *p++ = state->ref_frame.luma[i];
371 *p++ = state->ref_frame.cr[i];
375 case V4L2_PIX_FMT_ARGB32:
376 for (i = 0, p = p_out; i < size; i++) {
377 *p++ = state->ref_frame.alpha[i];
378 *p++ = state->ref_frame.cr[i];
379 *p++ = state->ref_frame.luma[i];
380 *p++ = state->ref_frame.cb[i];
383 case V4L2_PIX_FMT_ABGR32:
384 for (i = 0, p = p_out; i < size; i++) {
385 *p++ = state->ref_frame.cb[i];
386 *p++ = state->ref_frame.luma[i];
387 *p++ = state->ref_frame.cr[i];
388 *p++ = state->ref_frame.alpha[i];