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