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_ABGR32
, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB
},
33 { V4L2_PIX_FMT_RGB32
, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB
},
34 { V4L2_PIX_FMT_XRGB32
, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB
},
35 { V4L2_PIX_FMT_ARGB32
, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB
},
36 { V4L2_PIX_FMT_BGRX32
, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB
},
37 { V4L2_PIX_FMT_BGRA32
, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB
},
38 { V4L2_PIX_FMT_RGBX32
, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB
},
39 { V4L2_PIX_FMT_RGBA32
, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB
},
40 { V4L2_PIX_FMT_HSV32
, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV
},
41 { V4L2_PIX_FMT_GREY
, 1, 1, 1, 1, 0, 1, 1, 1, 1, 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 rf
->cr
= rf
->luma
+ 1;
182 case V4L2_PIX_FMT_BGR32
:
183 case V4L2_PIX_FMT_XBGR32
:
188 case V4L2_PIX_FMT_ARGB32
:
189 rf
->alpha
= rf
->luma
;
190 rf
->cr
= rf
->luma
+ 1;
194 case V4L2_PIX_FMT_ABGR32
:
198 rf
->alpha
= rf
->cr
+ 1;
200 case V4L2_PIX_FMT_BGRX32
:
201 rf
->cb
= rf
->luma
+ 1;
205 case V4L2_PIX_FMT_BGRA32
:
206 rf
->alpha
= rf
->luma
;
207 rf
->cb
= rf
->luma
+ 1;
211 case V4L2_PIX_FMT_RGBX32
:
216 case V4L2_PIX_FMT_RGBA32
:
217 rf
->alpha
= rf
->luma
+ 3;
228 int v4l2_fwht_encode(struct v4l2_fwht_state
*state
, u8
*p_in
, u8
*p_out
)
230 unsigned int size
= state
->stride
* state
->coded_height
;
231 unsigned int chroma_stride
= state
->stride
;
232 const struct v4l2_fwht_pixfmt_info
*info
= state
->info
;
233 struct fwht_cframe_hdr
*p_hdr
;
234 struct fwht_cframe cf
;
235 struct fwht_raw_frame rf
;
242 if (prepare_raw_frame(&rf
, info
, p_in
, size
))
245 if (info
->planes_num
== 3)
248 if (info
->id
== V4L2_PIX_FMT_NV24
||
249 info
->id
== V4L2_PIX_FMT_NV42
)
252 cf
.i_frame_qp
= state
->i_frame_qp
;
253 cf
.p_frame_qp
= state
->p_frame_qp
;
254 cf
.rlc_data
= (__be16
*)(p_out
+ sizeof(*p_hdr
));
256 encoding
= fwht_encode_frame(&rf
, &state
->ref_frame
, &cf
,
258 state
->gop_cnt
== state
->gop_size
- 1,
259 state
->visible_width
,
260 state
->visible_height
,
261 state
->stride
, chroma_stride
);
262 if (!(encoding
& FWHT_FRAME_PCODED
))
264 if (++state
->gop_cnt
>= state
->gop_size
)
267 p_hdr
= (struct fwht_cframe_hdr
*)p_out
;
268 p_hdr
->magic1
= FWHT_MAGIC1
;
269 p_hdr
->magic2
= FWHT_MAGIC2
;
270 p_hdr
->version
= htonl(FWHT_VERSION
);
271 p_hdr
->width
= htonl(state
->visible_width
);
272 p_hdr
->height
= htonl(state
->visible_height
);
273 flags
|= (info
->components_num
- 1) << FWHT_FL_COMPONENTS_NUM_OFFSET
;
274 flags
|= info
->pixenc
;
275 if (encoding
& FWHT_LUMA_UNENCODED
)
276 flags
|= FWHT_FL_LUMA_IS_UNCOMPRESSED
;
277 if (encoding
& FWHT_CB_UNENCODED
)
278 flags
|= FWHT_FL_CB_IS_UNCOMPRESSED
;
279 if (encoding
& FWHT_CR_UNENCODED
)
280 flags
|= FWHT_FL_CR_IS_UNCOMPRESSED
;
281 if (encoding
& FWHT_ALPHA_UNENCODED
)
282 flags
|= FWHT_FL_ALPHA_IS_UNCOMPRESSED
;
283 if (!(encoding
& FWHT_FRAME_PCODED
))
284 flags
|= FWHT_FL_I_FRAME
;
285 if (rf
.height_div
== 1)
286 flags
|= FWHT_FL_CHROMA_FULL_HEIGHT
;
287 if (rf
.width_div
== 1)
288 flags
|= FWHT_FL_CHROMA_FULL_WIDTH
;
289 p_hdr
->flags
= htonl(flags
);
290 p_hdr
->colorspace
= htonl(state
->colorspace
);
291 p_hdr
->xfer_func
= htonl(state
->xfer_func
);
292 p_hdr
->ycbcr_enc
= htonl(state
->ycbcr_enc
);
293 p_hdr
->quantization
= htonl(state
->quantization
);
294 p_hdr
->size
= htonl(cf
.size
);
295 return cf
.size
+ sizeof(*p_hdr
);
298 int v4l2_fwht_decode(struct v4l2_fwht_state
*state
, u8
*p_in
, u8
*p_out
)
301 struct fwht_cframe cf
;
302 unsigned int components_num
= 3;
303 unsigned int version
;
304 const struct v4l2_fwht_pixfmt_info
*info
;
305 unsigned int hdr_width_div
, hdr_height_div
;
306 struct fwht_raw_frame dst_rf
;
307 unsigned int dst_chroma_stride
= state
->stride
;
308 unsigned int ref_chroma_stride
= state
->ref_stride
;
309 unsigned int dst_size
= state
->stride
* state
->coded_height
;
310 unsigned int ref_size
;
317 version
= ntohl(state
->header
.version
);
318 if (!version
|| version
> FWHT_VERSION
) {
319 pr_err("version %d is not supported, current version is %d\n",
320 version
, FWHT_VERSION
);
324 if (state
->header
.magic1
!= FWHT_MAGIC1
||
325 state
->header
.magic2
!= FWHT_MAGIC2
)
328 /* TODO: support resolution changes */
329 if (ntohl(state
->header
.width
) != state
->visible_width
||
330 ntohl(state
->header
.height
) != state
->visible_height
)
333 flags
= ntohl(state
->header
.flags
);
336 if ((flags
& FWHT_FL_PIXENC_MSK
) != info
->pixenc
)
338 components_num
= 1 + ((flags
& FWHT_FL_COMPONENTS_NUM_MSK
) >>
339 FWHT_FL_COMPONENTS_NUM_OFFSET
);
342 if (components_num
!= info
->components_num
)
345 state
->colorspace
= ntohl(state
->header
.colorspace
);
346 state
->xfer_func
= ntohl(state
->header
.xfer_func
);
347 state
->ycbcr_enc
= ntohl(state
->header
.ycbcr_enc
);
348 state
->quantization
= ntohl(state
->header
.quantization
);
349 cf
.rlc_data
= (__be16
*)p_in
;
350 cf
.size
= ntohl(state
->header
.size
);
352 hdr_width_div
= (flags
& FWHT_FL_CHROMA_FULL_WIDTH
) ? 1 : 2;
353 hdr_height_div
= (flags
& FWHT_FL_CHROMA_FULL_HEIGHT
) ? 1 : 2;
354 if (hdr_width_div
!= info
->width_div
||
355 hdr_height_div
!= info
->height_div
)
358 if (prepare_raw_frame(&dst_rf
, info
, p_out
, dst_size
))
360 if (info
->planes_num
== 3) {
361 dst_chroma_stride
/= 2;
362 ref_chroma_stride
/= 2;
364 if (info
->id
== V4L2_PIX_FMT_NV24
||
365 info
->id
== V4L2_PIX_FMT_NV42
) {
366 dst_chroma_stride
*= 2;
367 ref_chroma_stride
*= 2;
371 ref_size
= state
->ref_stride
* state
->coded_height
;
373 if (prepare_raw_frame(&state
->ref_frame
, info
, state
->ref_frame
.buf
,
377 if (!fwht_decode_frame(&cf
, flags
, components_num
,
378 state
->visible_width
, state
->visible_height
,
379 &state
->ref_frame
, state
->ref_stride
, ref_chroma_stride
,
380 &dst_rf
, state
->stride
, dst_chroma_stride
))