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, 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
},
44 bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info
*info
,
45 u32 width_div
, u32 height_div
, u32 components_num
,
48 if (info
->width_div
== width_div
&&
49 info
->height_div
== height_div
&&
50 (!pixenc
|| info
->pixenc
== pixenc
) &&
51 info
->components_num
== components_num
)
56 const struct v4l2_fwht_pixfmt_info
*v4l2_fwht_find_nth_fmt(u32 width_div
,
60 unsigned int start_idx
)
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
);
70 return v4l2_fwht_pixfmts
+ i
;
77 const struct v4l2_fwht_pixfmt_info
*v4l2_fwht_find_pixfmt(u32 pixelformat
)
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
;
87 const struct v4l2_fwht_pixfmt_info
*v4l2_fwht_get_pixfmt(u32 idx
)
89 if (idx
>= ARRAY_SIZE(v4l2_fwht_pixfmts
))
91 return v4l2_fwht_pixfmts
+ idx
;
94 static int prepare_raw_frame(struct fwht_raw_frame
*rf
,
95 const struct v4l2_fwht_pixfmt_info
*info
, u8
*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
;
104 rf
->components_num
= info
->components_num
;
107 * The buffer is NULL if it is the reference
108 * frame of an I-frame in the stateless decoder
118 case V4L2_PIX_FMT_GREY
:
122 case V4L2_PIX_FMT_YUV420
:
123 rf
->cb
= rf
->luma
+ size
;
124 rf
->cr
= rf
->cb
+ size
/ 4;
126 case V4L2_PIX_FMT_YVU420
:
127 rf
->cr
= rf
->luma
+ size
;
128 rf
->cb
= rf
->cr
+ size
/ 4;
130 case V4L2_PIX_FMT_YUV422P
:
131 rf
->cb
= rf
->luma
+ size
;
132 rf
->cr
= rf
->cb
+ size
/ 2;
134 case V4L2_PIX_FMT_NV12
:
135 case V4L2_PIX_FMT_NV16
:
136 case V4L2_PIX_FMT_NV24
:
137 rf
->cb
= rf
->luma
+ size
;
140 case V4L2_PIX_FMT_NV21
:
141 case V4L2_PIX_FMT_NV61
:
142 case V4L2_PIX_FMT_NV42
:
143 rf
->cr
= rf
->luma
+ size
;
146 case V4L2_PIX_FMT_YUYV
:
147 rf
->cb
= rf
->luma
+ 1;
150 case V4L2_PIX_FMT_YVYU
:
151 rf
->cr
= rf
->luma
+ 1;
154 case V4L2_PIX_FMT_UYVY
:
159 case V4L2_PIX_FMT_VYUY
:
164 case V4L2_PIX_FMT_RGB24
:
165 case V4L2_PIX_FMT_HSV24
:
170 case V4L2_PIX_FMT_BGR24
:
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;
184 case V4L2_PIX_FMT_BGR32
:
185 case V4L2_PIX_FMT_XBGR32
:
186 case V4L2_PIX_FMT_ABGR32
:
190 rf
->alpha
= rf
->cr
+ 1;
192 case V4L2_PIX_FMT_BGRX32
:
193 case V4L2_PIX_FMT_BGRA32
:
194 rf
->alpha
= rf
->luma
;
195 rf
->cb
= rf
->luma
+ 1;
199 case V4L2_PIX_FMT_RGBX32
:
200 case V4L2_PIX_FMT_RGBA32
:
201 rf
->alpha
= rf
->luma
+ 3;
212 int v4l2_fwht_encode(struct v4l2_fwht_state
*state
, u8
*p_in
, u8
*p_out
)
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
;
226 if (prepare_raw_frame(&rf
, info
, p_in
, size
))
229 if (info
->planes_num
== 3)
232 if (info
->id
== V4L2_PIX_FMT_NV24
||
233 info
->id
== V4L2_PIX_FMT_NV42
)
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
));
240 encoding
= fwht_encode_frame(&rf
, &state
->ref_frame
, &cf
,
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
))
248 if (++state
->gop_cnt
>= state
->gop_size
)
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
);
282 int v4l2_fwht_decode(struct v4l2_fwht_state
*state
, u8
*p_in
, u8
*p_out
)
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
;
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
);
308 if (state
->header
.magic1
!= FWHT_MAGIC1
||
309 state
->header
.magic2
!= FWHT_MAGIC2
)
312 /* TODO: support resolution changes */
313 if (ntohl(state
->header
.width
) != state
->visible_width
||
314 ntohl(state
->header
.height
) != state
->visible_height
)
317 flags
= ntohl(state
->header
.flags
);
320 if ((flags
& V4L2_FWHT_FL_PIXENC_MSK
) != info
->pixenc
)
322 components_num
= 1 + ((flags
& V4L2_FWHT_FL_COMPONENTS_NUM_MSK
) >>
323 V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET
);
326 if (components_num
!= info
->components_num
)
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
);
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
)
342 if (prepare_raw_frame(&dst_rf
, info
, p_out
, dst_size
))
344 if (info
->planes_num
== 3) {
345 dst_chroma_stride
/= 2;
346 ref_chroma_stride
/= 2;
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;
355 ref_size
= state
->ref_stride
* state
->coded_height
;
357 if (prepare_raw_frame(&state
->ref_frame
, info
, state
->ref_frame
.buf
,
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
))