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},
15 { V4L2_PIX_FMT_YVU420
, 1, 3, 2, 1, 1, 2, 2, 3},
16 { V4L2_PIX_FMT_YUV422P
, 1, 2, 1, 1, 1, 2, 1, 3},
17 { V4L2_PIX_FMT_NV12
, 1, 3, 2, 1, 2, 2, 2, 3},
18 { V4L2_PIX_FMT_NV21
, 1, 3, 2, 1, 2, 2, 2, 3},
19 { V4L2_PIX_FMT_NV16
, 1, 2, 1, 1, 2, 2, 1, 3},
20 { V4L2_PIX_FMT_NV61
, 1, 2, 1, 1, 2, 2, 1, 3},
21 { V4L2_PIX_FMT_NV24
, 1, 3, 1, 1, 2, 1, 1, 3},
22 { V4L2_PIX_FMT_NV42
, 1, 3, 1, 1, 2, 1, 1, 3},
23 { V4L2_PIX_FMT_YUYV
, 2, 2, 1, 2, 4, 2, 1, 3},
24 { V4L2_PIX_FMT_YVYU
, 2, 2, 1, 2, 4, 2, 1, 3},
25 { V4L2_PIX_FMT_UYVY
, 2, 2, 1, 2, 4, 2, 1, 3},
26 { V4L2_PIX_FMT_VYUY
, 2, 2, 1, 2, 4, 2, 1, 3},
27 { V4L2_PIX_FMT_BGR24
, 3, 3, 1, 3, 3, 1, 1, 3},
28 { V4L2_PIX_FMT_RGB24
, 3, 3, 1, 3, 3, 1, 1, 3},
29 { V4L2_PIX_FMT_HSV24
, 3, 3, 1, 3, 3, 1, 1, 3},
30 { V4L2_PIX_FMT_BGR32
, 4, 4, 1, 4, 4, 1, 1, 3},
31 { V4L2_PIX_FMT_XBGR32
, 4, 4, 1, 4, 4, 1, 1, 3},
32 { V4L2_PIX_FMT_RGB32
, 4, 4, 1, 4, 4, 1, 1, 3},
33 { V4L2_PIX_FMT_XRGB32
, 4, 4, 1, 4, 4, 1, 1, 3},
34 { V4L2_PIX_FMT_HSV32
, 4, 4, 1, 4, 4, 1, 1, 3},
35 { V4L2_PIX_FMT_ARGB32
, 4, 4, 1, 4, 4, 1, 1, 4},
36 { V4L2_PIX_FMT_ABGR32
, 4, 4, 1, 4, 4, 1, 1, 4},
37 { V4L2_PIX_FMT_GREY
, 1, 1, 1, 1, 0, 1, 1, 1},
40 const struct v4l2_fwht_pixfmt_info
*v4l2_fwht_find_pixfmt(u32 pixelformat
)
44 for (i
= 0; i
< ARRAY_SIZE(v4l2_fwht_pixfmts
); i
++)
45 if (v4l2_fwht_pixfmts
[i
].id
== pixelformat
)
46 return v4l2_fwht_pixfmts
+ i
;
50 const struct v4l2_fwht_pixfmt_info
*v4l2_fwht_get_pixfmt(u32 idx
)
52 if (idx
>= ARRAY_SIZE(v4l2_fwht_pixfmts
))
54 return v4l2_fwht_pixfmts
+ idx
;
57 int v4l2_fwht_encode(struct v4l2_fwht_state
*state
, u8
*p_in
, u8
*p_out
)
59 unsigned int size
= state
->width
* state
->height
;
60 const struct v4l2_fwht_pixfmt_info
*info
= state
->info
;
61 struct fwht_cframe_hdr
*p_hdr
;
62 struct fwht_cframe cf
;
63 struct fwht_raw_frame rf
;
69 rf
.width
= state
->width
;
70 rf
.height
= state
->height
;
72 rf
.width_div
= info
->width_div
;
73 rf
.height_div
= info
->height_div
;
74 rf
.luma_alpha_step
= info
->luma_alpha_step
;
75 rf
.chroma_step
= info
->chroma_step
;
77 rf
.components_num
= info
->components_num
;
80 case V4L2_PIX_FMT_GREY
:
84 case V4L2_PIX_FMT_YUV420
:
85 rf
.cb
= rf
.luma
+ size
;
86 rf
.cr
= rf
.cb
+ size
/ 4;
88 case V4L2_PIX_FMT_YVU420
:
89 rf
.cr
= rf
.luma
+ size
;
90 rf
.cb
= rf
.cr
+ size
/ 4;
92 case V4L2_PIX_FMT_YUV422P
:
93 rf
.cb
= rf
.luma
+ size
;
94 rf
.cr
= rf
.cb
+ size
/ 2;
96 case V4L2_PIX_FMT_NV12
:
97 case V4L2_PIX_FMT_NV16
:
98 case V4L2_PIX_FMT_NV24
:
99 rf
.cb
= rf
.luma
+ size
;
102 case V4L2_PIX_FMT_NV21
:
103 case V4L2_PIX_FMT_NV61
:
104 case V4L2_PIX_FMT_NV42
:
105 rf
.cr
= rf
.luma
+ size
;
108 case V4L2_PIX_FMT_YUYV
:
112 case V4L2_PIX_FMT_YVYU
:
116 case V4L2_PIX_FMT_UYVY
:
121 case V4L2_PIX_FMT_VYUY
:
126 case V4L2_PIX_FMT_RGB24
:
127 case V4L2_PIX_FMT_HSV24
:
132 case V4L2_PIX_FMT_BGR24
:
137 case V4L2_PIX_FMT_RGB32
:
138 case V4L2_PIX_FMT_XRGB32
:
139 case V4L2_PIX_FMT_HSV32
:
144 case V4L2_PIX_FMT_BGR32
:
145 case V4L2_PIX_FMT_XBGR32
:
150 case V4L2_PIX_FMT_ARGB32
:
156 case V4L2_PIX_FMT_ABGR32
:
160 rf
.alpha
= rf
.cr
+ 1;
166 cf
.width
= state
->width
;
167 cf
.height
= state
->height
;
168 cf
.i_frame_qp
= state
->i_frame_qp
;
169 cf
.p_frame_qp
= state
->p_frame_qp
;
170 cf
.rlc_data
= (__be16
*)(p_out
+ sizeof(*p_hdr
));
172 encoding
= fwht_encode_frame(&rf
, &state
->ref_frame
, &cf
,
174 state
->gop_cnt
== state
->gop_size
- 1);
175 if (!(encoding
& FWHT_FRAME_PCODED
))
177 if (++state
->gop_cnt
>= state
->gop_size
)
180 p_hdr
= (struct fwht_cframe_hdr
*)p_out
;
181 p_hdr
->magic1
= FWHT_MAGIC1
;
182 p_hdr
->magic2
= FWHT_MAGIC2
;
183 p_hdr
->version
= htonl(FWHT_VERSION
);
184 p_hdr
->width
= htonl(cf
.width
);
185 p_hdr
->height
= htonl(cf
.height
);
186 flags
|= (info
->components_num
- 1) << FWHT_FL_COMPONENTS_NUM_OFFSET
;
187 if (encoding
& FWHT_LUMA_UNENCODED
)
188 flags
|= FWHT_FL_LUMA_IS_UNCOMPRESSED
;
189 if (encoding
& FWHT_CB_UNENCODED
)
190 flags
|= FWHT_FL_CB_IS_UNCOMPRESSED
;
191 if (encoding
& FWHT_CR_UNENCODED
)
192 flags
|= FWHT_FL_CR_IS_UNCOMPRESSED
;
193 if (encoding
& FWHT_ALPHA_UNENCODED
)
194 flags
|= FWHT_FL_ALPHA_IS_UNCOMPRESSED
;
195 if (rf
.height_div
== 1)
196 flags
|= FWHT_FL_CHROMA_FULL_HEIGHT
;
197 if (rf
.width_div
== 1)
198 flags
|= FWHT_FL_CHROMA_FULL_WIDTH
;
199 p_hdr
->flags
= htonl(flags
);
200 p_hdr
->colorspace
= htonl(state
->colorspace
);
201 p_hdr
->xfer_func
= htonl(state
->xfer_func
);
202 p_hdr
->ycbcr_enc
= htonl(state
->ycbcr_enc
);
203 p_hdr
->quantization
= htonl(state
->quantization
);
204 p_hdr
->size
= htonl(cf
.size
);
205 state
->ref_frame
.width
= cf
.width
;
206 state
->ref_frame
.height
= cf
.height
;
207 return cf
.size
+ sizeof(*p_hdr
);
210 int v4l2_fwht_decode(struct v4l2_fwht_state
*state
, u8
*p_in
, u8
*p_out
)
212 unsigned int size
= state
->width
* state
->height
;
213 unsigned int chroma_size
= size
;
216 struct fwht_cframe_hdr
*p_hdr
;
217 struct fwht_cframe cf
;
219 unsigned int components_num
= 3;
220 unsigned int version
;
225 p_hdr
= (struct fwht_cframe_hdr
*)p_in
;
226 cf
.width
= ntohl(p_hdr
->width
);
227 cf
.height
= ntohl(p_hdr
->height
);
229 version
= ntohl(p_hdr
->version
);
230 if (!version
|| version
> FWHT_VERSION
) {
231 pr_err("version %d is not supported, current version is %d\n",
232 version
, FWHT_VERSION
);
236 if (p_hdr
->magic1
!= FWHT_MAGIC1
||
237 p_hdr
->magic2
!= FWHT_MAGIC2
||
238 (cf
.width
& 7) || (cf
.height
& 7))
241 /* TODO: support resolution changes */
242 if (cf
.width
!= state
->width
|| cf
.height
!= state
->height
)
245 flags
= ntohl(p_hdr
->flags
);
247 if (version
== FWHT_VERSION
) {
248 components_num
= 1 + ((flags
& FWHT_FL_COMPONENTS_NUM_MSK
) >>
249 FWHT_FL_COMPONENTS_NUM_OFFSET
);
252 state
->colorspace
= ntohl(p_hdr
->colorspace
);
253 state
->xfer_func
= ntohl(p_hdr
->xfer_func
);
254 state
->ycbcr_enc
= ntohl(p_hdr
->ycbcr_enc
);
255 state
->quantization
= ntohl(p_hdr
->quantization
);
256 cf
.rlc_data
= (__be16
*)(p_in
+ sizeof(*p_hdr
));
258 if (!(flags
& FWHT_FL_CHROMA_FULL_WIDTH
))
260 if (!(flags
& FWHT_FL_CHROMA_FULL_HEIGHT
))
263 fwht_decode_frame(&cf
, &state
->ref_frame
, flags
, components_num
);
266 * TODO - handle the case where the compressed stream encodes a
267 * different format than the requested decoded format.
269 switch (state
->info
->id
) {
270 case V4L2_PIX_FMT_GREY
:
271 memcpy(p_out
, state
->ref_frame
.luma
, size
);
273 case V4L2_PIX_FMT_YUV420
:
274 case V4L2_PIX_FMT_YUV422P
:
275 memcpy(p_out
, state
->ref_frame
.luma
, size
);
277 memcpy(p_out
, state
->ref_frame
.cb
, chroma_size
);
278 p_out
+= chroma_size
;
279 memcpy(p_out
, state
->ref_frame
.cr
, chroma_size
);
281 case V4L2_PIX_FMT_YVU420
:
282 memcpy(p_out
, state
->ref_frame
.luma
, size
);
284 memcpy(p_out
, state
->ref_frame
.cr
, chroma_size
);
285 p_out
+= chroma_size
;
286 memcpy(p_out
, state
->ref_frame
.cb
, chroma_size
);
288 case V4L2_PIX_FMT_NV12
:
289 case V4L2_PIX_FMT_NV16
:
290 case V4L2_PIX_FMT_NV24
:
291 memcpy(p_out
, state
->ref_frame
.luma
, size
);
293 for (i
= 0, p
= p_out
; i
< chroma_size
; i
++) {
294 *p
++ = state
->ref_frame
.cb
[i
];
295 *p
++ = state
->ref_frame
.cr
[i
];
298 case V4L2_PIX_FMT_NV21
:
299 case V4L2_PIX_FMT_NV61
:
300 case V4L2_PIX_FMT_NV42
:
301 memcpy(p_out
, state
->ref_frame
.luma
, size
);
303 for (i
= 0, p
= p_out
; i
< chroma_size
; i
++) {
304 *p
++ = state
->ref_frame
.cr
[i
];
305 *p
++ = state
->ref_frame
.cb
[i
];
308 case V4L2_PIX_FMT_YUYV
:
309 for (i
= 0, p
= p_out
; i
< size
; i
+= 2) {
310 *p
++ = state
->ref_frame
.luma
[i
];
311 *p
++ = state
->ref_frame
.cb
[i
/ 2];
312 *p
++ = state
->ref_frame
.luma
[i
+ 1];
313 *p
++ = state
->ref_frame
.cr
[i
/ 2];
316 case V4L2_PIX_FMT_YVYU
:
317 for (i
= 0, p
= p_out
; i
< size
; i
+= 2) {
318 *p
++ = state
->ref_frame
.luma
[i
];
319 *p
++ = state
->ref_frame
.cr
[i
/ 2];
320 *p
++ = state
->ref_frame
.luma
[i
+ 1];
321 *p
++ = state
->ref_frame
.cb
[i
/ 2];
324 case V4L2_PIX_FMT_UYVY
:
325 for (i
= 0, p
= p_out
; i
< size
; i
+= 2) {
326 *p
++ = state
->ref_frame
.cb
[i
/ 2];
327 *p
++ = state
->ref_frame
.luma
[i
];
328 *p
++ = state
->ref_frame
.cr
[i
/ 2];
329 *p
++ = state
->ref_frame
.luma
[i
+ 1];
332 case V4L2_PIX_FMT_VYUY
:
333 for (i
= 0, p
= p_out
; i
< size
; i
+= 2) {
334 *p
++ = state
->ref_frame
.cr
[i
/ 2];
335 *p
++ = state
->ref_frame
.luma
[i
];
336 *p
++ = state
->ref_frame
.cb
[i
/ 2];
337 *p
++ = state
->ref_frame
.luma
[i
+ 1];
340 case V4L2_PIX_FMT_RGB24
:
341 case V4L2_PIX_FMT_HSV24
:
342 for (i
= 0, p
= p_out
; i
< size
; i
++) {
343 *p
++ = state
->ref_frame
.cr
[i
];
344 *p
++ = state
->ref_frame
.luma
[i
];
345 *p
++ = state
->ref_frame
.cb
[i
];
348 case V4L2_PIX_FMT_BGR24
:
349 for (i
= 0, p
= p_out
; i
< size
; i
++) {
350 *p
++ = state
->ref_frame
.cb
[i
];
351 *p
++ = state
->ref_frame
.luma
[i
];
352 *p
++ = state
->ref_frame
.cr
[i
];
355 case V4L2_PIX_FMT_RGB32
:
356 case V4L2_PIX_FMT_XRGB32
:
357 case V4L2_PIX_FMT_HSV32
:
358 for (i
= 0, p
= p_out
; i
< size
; i
++) {
360 *p
++ = state
->ref_frame
.cr
[i
];
361 *p
++ = state
->ref_frame
.luma
[i
];
362 *p
++ = state
->ref_frame
.cb
[i
];
365 case V4L2_PIX_FMT_BGR32
:
366 case V4L2_PIX_FMT_XBGR32
:
367 for (i
= 0, p
= p_out
; i
< size
; i
++) {
368 *p
++ = state
->ref_frame
.cb
[i
];
369 *p
++ = state
->ref_frame
.luma
[i
];
370 *p
++ = state
->ref_frame
.cr
[i
];
374 case V4L2_PIX_FMT_ARGB32
:
375 for (i
= 0, p
= p_out
; i
< size
; i
++) {
376 *p
++ = state
->ref_frame
.alpha
[i
];
377 *p
++ = state
->ref_frame
.cr
[i
];
378 *p
++ = state
->ref_frame
.luma
[i
];
379 *p
++ = state
->ref_frame
.cb
[i
];
382 case V4L2_PIX_FMT_ABGR32
:
383 for (i
= 0, p
= p_out
; i
< size
; i
++) {
384 *p
++ = state
->ref_frame
.cb
[i
];
385 *p
++ = state
->ref_frame
.luma
[i
];
386 *p
++ = state
->ref_frame
.cr
[i
];
387 *p
++ = state
->ref_frame
.alpha
[i
];