1 // SPDX-License-Identifier: LGPL-2.1-only
2 /*
3 * V4L2 run-length image encoder source
4 *
5 * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 */
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <netinet/in.h>
11
12 #include "v4l-stream.h"
13 #include "codec-fwht.h"
14
15 #define MIN_WIDTH 64
16 #define MAX_WIDTH 4096
17 #define MIN_HEIGHT 64
18 #define MAX_HEIGHT 2160
19
20 /*
21 * Since Bayer uses alternating lines of BG and GR color components
22 * you cannot compare one line with the next to see if they are identical,
23 * instead you need to look at two consecutive lines at a time.
24 * So here we double the bytesperline value for Bayer formats.
25 */
rle_calc_bpl(unsigned bpl,uint32_t pixelformat)26 unsigned rle_calc_bpl(unsigned bpl, uint32_t pixelformat)
27 {
28 switch (pixelformat) {
29 case V4L2_PIX_FMT_SBGGR8:
30 case V4L2_PIX_FMT_SGBRG8:
31 case V4L2_PIX_FMT_SGRBG8:
32 case V4L2_PIX_FMT_SRGGB8:
33 case V4L2_PIX_FMT_SBGGR10:
34 case V4L2_PIX_FMT_SGBRG10:
35 case V4L2_PIX_FMT_SGRBG10:
36 case V4L2_PIX_FMT_SRGGB10:
37 case V4L2_PIX_FMT_SBGGR10P:
38 case V4L2_PIX_FMT_SGBRG10P:
39 case V4L2_PIX_FMT_SGRBG10P:
40 case V4L2_PIX_FMT_SRGGB10P:
41 case V4L2_PIX_FMT_SBGGR10ALAW8:
42 case V4L2_PIX_FMT_SGBRG10ALAW8:
43 case V4L2_PIX_FMT_SGRBG10ALAW8:
44 case V4L2_PIX_FMT_SRGGB10ALAW8:
45 case V4L2_PIX_FMT_SBGGR10DPCM8:
46 case V4L2_PIX_FMT_SGBRG10DPCM8:
47 case V4L2_PIX_FMT_SGRBG10DPCM8:
48 case V4L2_PIX_FMT_SRGGB10DPCM8:
49 case V4L2_PIX_FMT_SBGGR12:
50 case V4L2_PIX_FMT_SGBRG12:
51 case V4L2_PIX_FMT_SGRBG12:
52 case V4L2_PIX_FMT_SRGGB12:
53 case V4L2_PIX_FMT_SBGGR16:
54 case V4L2_PIX_FMT_SGBRG16:
55 case V4L2_PIX_FMT_SGRBG16:
56 case V4L2_PIX_FMT_SRGGB16:
57 return 2 * bpl;
58 default:
59 return bpl;
60 }
61 }
62
rle_decompress(uint8_t * b,unsigned size,unsigned rle_size,unsigned bpl)63 void rle_decompress(uint8_t *b, unsigned size, unsigned rle_size, unsigned bpl)
64 {
65 uint32_t magic_x = ntohl(V4L_STREAM_PACKET_FRAME_VIDEO_X_RLE);
66 uint32_t magic_y = ntohl(V4L_STREAM_PACKET_FRAME_VIDEO_Y_RLE);
67 unsigned offset = size - rle_size;
68 uint32_t *dst = (uint32_t *)b;
69 uint32_t *p = (uint32_t *)(b + offset);
70 uint32_t *next_line = NULL;
71 unsigned l = 0;
72 unsigned i;
73
74 if (size == rle_size)
75 return;
76
77 if (bpl & 3)
78 bpl = 0;
79 if (bpl == 0)
80 magic_y = magic_x;
81
82 for (i = 0; i < rle_size; i += 4, p++) {
83 uint32_t v = *p;
84 uint32_t n = 1;
85
86 if (bpl && v == magic_y) {
87 l = ntohl(*++p);
88 i += 4;
89 next_line = dst + bpl / 4;
90 continue;
91 }
92 if (v == magic_x) {
93 v = *++p;
94 n = ntohl(*++p);
95 i += 8;
96 }
97
98 while (n--)
99 *dst++ = v;
100
101 if (dst == next_line) {
102 while (l--) {
103 memcpy(dst, dst - bpl / 4, bpl);
104 dst += bpl / 4;
105 }
106 next_line = NULL;
107 }
108 }
109 }
110
rle_compress(uint8_t * b,unsigned size,unsigned bpl)111 unsigned rle_compress(uint8_t *b, unsigned size, unsigned bpl)
112 {
113 uint32_t magic_x = ntohl(V4L_STREAM_PACKET_FRAME_VIDEO_X_RLE);
114 uint32_t magic_y = ntohl(V4L_STREAM_PACKET_FRAME_VIDEO_Y_RLE);
115 uint32_t magic_r = ntohl(V4L_STREAM_PACKET_FRAME_VIDEO_RPLC);
116 uint32_t *p = (uint32_t *)b;
117 uint32_t *dst = p;
118 unsigned i;
119
120 /*
121 * Only attempt runlength encoding if b is aligned
122 * to a multiple of 4 bytes and if size is a multiple of 4.
123 */
124 if (((unsigned long)b & 3) || (size & 3))
125 return size;
126
127 if (bpl & 3)
128 bpl = 0;
129 if (bpl == 0)
130 magic_y = magic_x;
131
132 for (i = 0; i < size; i += 4, p++) {
133 unsigned n, max;
134
135 if (bpl && i % bpl == 0) {
136 unsigned l = 0;
137
138 while (i + (l + 2) * bpl <= size &&
139 !memcmp(p, p + (l + 1) * (bpl / 4), bpl))
140 l++;
141 if (l) {
142 *dst++ = magic_y;
143 *dst++ = htonl(l);
144 i += l * bpl - 4;
145 p += (l * bpl / 4) - 1;
146 continue;
147 }
148 }
149 if (*p == magic_x || *p == magic_y) {
150 *dst++ = magic_r;
151 continue;
152 }
153 max = bpl ? bpl * (i / bpl + 1) : size;
154 if (i >= max - 16) {
155 *dst++ = *p;
156 continue;
157 }
158 if (*p != p[1] || *p != p[2] || *p != p[3]) {
159 *dst++ = *p;
160 continue;
161 }
162 n = 4;
163
164 while (i + n * 4 < max && *p == p[n])
165 n++;
166 *dst++ = magic_x;
167 *dst++ = p[1];
168 *dst++ = htonl(n);
169 p += n - 1;
170 i += n * 4 - 4;
171 }
172 return (uint8_t *)dst - b;
173 }
174
fwht_alloc(unsigned pixfmt,unsigned visible_width,unsigned visible_height,unsigned coded_width,unsigned coded_height,unsigned field,unsigned colorspace,unsigned xfer_func,unsigned ycbcr_enc,unsigned quantization)175 struct codec_ctx *fwht_alloc(unsigned pixfmt, unsigned visible_width, unsigned visible_height,
176 unsigned coded_width, unsigned coded_height,
177 unsigned field, unsigned colorspace, unsigned xfer_func,
178 unsigned ycbcr_enc, unsigned quantization)
179 {
180 struct codec_ctx *ctx;
181 const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_find_pixfmt(pixfmt);
182 unsigned int chroma_div;
183 unsigned int size = coded_width * coded_height;
184
185 // fwht expects macroblock alignment, check can be dropped once that
186 // restriction is lifted.
187 if (!info || coded_width % 8 || coded_height % 8)
188 return NULL;
189
190 ctx = malloc(sizeof(*ctx));
191 if (!ctx)
192 return NULL;
193 ctx->state.coded_width = coded_width;
194 ctx->state.coded_height = coded_height;
195 ctx->state.visible_width = visible_width;
196 ctx->state.visible_height = visible_height;
197 ctx->state.stride = coded_width * info->bytesperline_mult;
198 ctx->state.ref_stride = coded_width * info->luma_alpha_step;
199 ctx->state.info = info;
200 ctx->field = field;
201 ctx->state.colorspace = colorspace;
202 ctx->state.xfer_func = xfer_func;
203 ctx->state.ycbcr_enc = ycbcr_enc;
204 ctx->state.quantization = quantization;
205 ctx->flags = 0;
206 chroma_div = info->width_div * info->height_div;
207 ctx->size = size;
208 if (info->components_num == 4)
209 ctx->size = 2 * size + 2 * (size / chroma_div);
210 else if (info->components_num == 3)
211 ctx->size = size + 2 * (size / chroma_div);
212 ctx->state.ref_frame.buf = malloc(ctx->size);
213 ctx->state.ref_frame.luma = ctx->state.ref_frame.buf;
214 ctx->comp_max_size = ctx->size + sizeof(struct fwht_cframe_hdr);
215 ctx->state.compressed_frame = malloc(ctx->comp_max_size);
216 if (!ctx->state.ref_frame.luma || !ctx->state.compressed_frame) {
217 free(ctx->state.ref_frame.luma);
218 free(ctx->state.compressed_frame);
219 free(ctx);
220 return NULL;
221 }
222 if (info->components_num >= 3) {
223 ctx->state.ref_frame.cb = ctx->state.ref_frame.luma + size;
224 ctx->state.ref_frame.cr = ctx->state.ref_frame.cb + size / chroma_div;
225 } else {
226 ctx->state.ref_frame.cb = NULL;
227 ctx->state.ref_frame.cr = NULL;
228 }
229
230 if (info->components_num == 4)
231 ctx->state.ref_frame.alpha =
232 ctx->state.ref_frame.cr + size / chroma_div;
233 else
234 ctx->state.ref_frame.alpha = NULL;
235 ctx->state.gop_size = 10;
236 ctx->state.gop_cnt = 0;
237 return ctx;
238 }
239
fwht_free(struct codec_ctx * ctx)240 void fwht_free(struct codec_ctx *ctx)
241 {
242 free(ctx->state.ref_frame.luma);
243 free(ctx->state.compressed_frame);
244 free(ctx);
245 }
246
fwht_compress(struct codec_ctx * ctx,uint8_t * buf,unsigned uncomp_size,unsigned * comp_size)247 uint8_t *fwht_compress(struct codec_ctx *ctx, uint8_t *buf, unsigned uncomp_size, unsigned *comp_size)
248 {
249 ctx->state.i_frame_qp = ctx->state.p_frame_qp = 20;
250 *comp_size = v4l2_fwht_encode(&ctx->state, buf, ctx->state.compressed_frame);
251 return ctx->state.compressed_frame;
252 }
253
copy_cap_to_ref(const u8 * cap,const struct v4l2_fwht_pixfmt_info * info,struct v4l2_fwht_state * state)254 static void copy_cap_to_ref(const u8 *cap, const struct v4l2_fwht_pixfmt_info *info,
255 struct v4l2_fwht_state *state)
256 {
257 int plane_idx;
258 u8 *p_ref = state->ref_frame.buf;
259 unsigned int cap_stride = state->stride;
260 unsigned int ref_stride = state->ref_stride;
261
262 for (plane_idx = 0; plane_idx < info->planes_num; plane_idx++) {
263 int i;
264 unsigned int h_div = (plane_idx == 1 || plane_idx == 2) ?
265 info->height_div : 1;
266 const u8 *row_cap = cap;
267 u8 *row_ref = p_ref;
268
269 if (info->planes_num == 3 && plane_idx == 1) {
270 cap_stride /= 2;
271 ref_stride /= 2;
272 }
273
274 if (plane_idx == 1 &&
275 (info->id == V4L2_PIX_FMT_NV24 ||
276 info->id == V4L2_PIX_FMT_NV42)) {
277 cap_stride *= 2;
278 ref_stride *= 2;
279 }
280
281 for (i = 0; i < state->visible_height / h_div; i++) {
282 memcpy(row_ref, row_cap, ref_stride);
283 row_ref += ref_stride;
284 row_cap += cap_stride;
285 }
286 cap += cap_stride * (state->coded_height / h_div);
287 p_ref += ref_stride * (state->coded_height / h_div);
288 }
289 }
290
fwht_decompress(struct codec_ctx * ctx,uint8_t * p_in,unsigned comp_size,uint8_t * p_out,unsigned uncomp_size)291 bool fwht_decompress(struct codec_ctx *ctx, uint8_t *p_in, unsigned comp_size,
292 uint8_t *p_out, unsigned uncomp_size)
293 {
294 memcpy(&ctx->state.header, p_in, sizeof(ctx->state.header));
295 p_in += sizeof(ctx->state.header);
296 if (v4l2_fwht_decode(&ctx->state, p_in, p_out))
297 return false;
298 copy_cap_to_ref(p_out, ctx->state.info, &ctx->state);
299 return true;
300 }
301