1 /**
2 * librfxcodec: A Remote Desktop Protocol client.
3 * RemoteFX Codec Library
4 *
5 * Copyright 2015-2017 Jay Sorg <jay.sorg@gmail.com>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #if defined(HAVE_CONFIG_H)
21 #include <config_ac.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <rfxcodec_encode.h>
29
30 #include "rfxcommon.h"
31 #include "rfxencode.h"
32 #include "rfxconstants.h"
33 #include "rfxencode_tile.h"
34
35 #define LLOG_LEVEL 1
36 #define LLOGLN(_level, _args) \
37 do { if (_level < LLOG_LEVEL) { printf _args ; printf("\n"); } } while (0)
38
39 #if 1
40 /*****************************************************************************/
41 static int
fdelta(const char * in_plane,char * out_plane,int cx,int cy)42 fdelta(const char *in_plane, char *out_plane, int cx, int cy)
43 {
44 char delta;
45 const char *src8;
46 char *dst8;
47 int index;
48 int jndex;
49
50 memcpy(out_plane, in_plane, cx);
51 src8 = in_plane;
52 dst8 = out_plane;
53 for (jndex = 1; jndex < cy; jndex++)
54 {
55 for (index = 0; index < cx; index++)
56 {
57 delta = src8[cx] - src8[0];
58 if (delta & 0x80)
59 {
60 delta = (((~delta) + 1) << 1) - 1;
61 }
62 else
63 {
64 delta = delta << 1;
65 }
66 dst8[cx] = delta;
67 src8++;
68 dst8++;
69 }
70 }
71 return 0;
72 }
73 #endif
74
75 #if 0
76 /*****************************************************************************/
77 #define DELTA_ONE \
78 do { \
79 delta = src8[cx] - src8[0]; \
80 is_neg = (delta >> 7) & 1; \
81 dst8[cx] = (((delta ^ -is_neg) + is_neg) << 1) - is_neg; \
82 src8++; \
83 dst8++; \
84 } while (0)
85
86 /*****************************************************************************/
87 static int
88 fdelta(char *in_plane, char *out_plane, int cx, int cy)
89 {
90 char delta;
91 char is_neg;
92 char *src8;
93 char *dst8;
94 char *src8_end;
95
96 memcpy(out_plane, in_plane, cx);
97 src8 = in_plane;
98 dst8 = out_plane;
99 src8_end = src8 + (cx * cy - cx);
100 while (src8 + 8 <= src8_end)
101 {
102 DELTA_ONE;
103 DELTA_ONE;
104 DELTA_ONE;
105 DELTA_ONE;
106 DELTA_ONE;
107 DELTA_ONE;
108 DELTA_ONE;
109 DELTA_ONE;
110 }
111 while (src8 < src8_end)
112 {
113 DELTA_ONE;
114 }
115 return 0;
116 }
117 #endif
118
119 /*****************************************************************************/
120 static int
fout(int collen,int replen,char * colptr,STREAM * s)121 fout(int collen, int replen, char *colptr, STREAM *s)
122 {
123 int code;
124 int lcollen;
125 int lreplen;
126 int cont;
127
128 LLOGLN(10, ("fout: collen %d replen %d", collen, replen));
129 cont = collen > 13;
130 while (cont)
131 {
132 lcollen = collen;
133 if (lcollen > 15)
134 {
135 lcollen = 15;
136 }
137 code = lcollen << 4;
138 stream_write_uint8(s, code);
139 memcpy(s->p, colptr, lcollen);
140 s->p += lcollen;
141 colptr += lcollen;
142 collen -= lcollen;
143 cont = collen > 13;
144 }
145 cont = (collen > 0) || (replen > 0);
146 while (cont)
147 {
148 lreplen = replen;
149 if ((collen == 0) && (lreplen > 15))
150 {
151 /* big run */
152 if (lreplen > 47)
153 {
154 lreplen = 47;
155 }
156 LLOGLN(10, ("fout: big run lreplen %d", lreplen));
157 replen -= lreplen;
158 code = ((lreplen & 0xF) << 4) | ((lreplen & 0xF0) >> 4);
159 stream_write_uint8(s, code);
160 colptr += lreplen;
161 }
162 else
163 {
164 if (lreplen > 15)
165 {
166 lreplen = 15;
167 }
168 replen -= lreplen;
169 if (lreplen < 3)
170 {
171 collen += lreplen;
172 lreplen = 0;
173 }
174 code = (collen << 4) | lreplen;
175 stream_write_uint8(s, code);
176 memcpy(s->p, colptr, collen);
177 s->p += collen;
178 colptr += collen + lreplen;
179 collen = 0;
180 }
181 cont = replen > 0;
182 }
183 return 0;
184 }
185
186 /*****************************************************************************/
187 static int
fpack(char * plane,int cx,int cy,STREAM * s)188 fpack(char *plane, int cx, int cy, STREAM *s)
189 {
190 char *ptr8;
191 char *colptr;
192 char *lend;
193 uint8 *holdp;
194 int jndex;
195 int collen;
196 int replen;
197
198 LLOGLN(10, ("fpack:"));
199 holdp = s->p;
200 for (jndex = 0; jndex < cy; jndex++)
201 {
202 LLOGLN(10, ("line start line %d cx %d cy %d", jndex, cx, cy));
203 ptr8 = (char *) (plane + jndex * cx);
204 lend = ptr8 + (cx - 1);
205 colptr = ptr8;
206 if (colptr[0] == 0)
207 {
208 collen = 0;
209 replen = 1;
210 }
211 else
212 {
213 collen = 1;
214 replen = 0;
215 }
216 while (ptr8 < lend)
217 {
218 if (ptr8[0] == ptr8[1])
219 {
220 replen++;
221 }
222 else
223 {
224 if (replen > 0)
225 {
226 if (replen < 3)
227 {
228 collen += replen + 1;
229 replen = 0;
230 }
231 else
232 {
233 fout(collen, replen, colptr, s);
234 colptr = ptr8 + 1;
235 replen = 0;
236 collen = 1;
237 }
238 }
239 else
240 {
241 collen++;
242 }
243 }
244 ptr8++;
245 }
246 /* end of line */
247 fout(collen, replen, colptr, s);
248 }
249 return (int) (s->p - holdp);
250 }
251
252 /*****************************************************************************/
253 int
rfx_encode_plane(struct rfxencode * enc,const uint8 * plane,int cx,int cy,STREAM * s)254 rfx_encode_plane(struct rfxencode *enc, const uint8 *plane, int cx, int cy,
255 STREAM *s)
256 {
257 const char *org_plane;
258 char *delta_plane;
259 int bytes;
260 uint8 *holdp;
261
262 org_plane = (const char *) plane;
263 delta_plane = (char *) (enc->dwt_buffer1);
264 fdelta(org_plane, delta_plane, cx, cy);
265 holdp = s->p;
266 stream_write_uint8(s, 0x10); /* flags, RLE */
267 bytes = fpack(delta_plane, cx, cy, s);
268 if (bytes > cx * cy)
269 {
270 LLOGLN(10, ("rfx_encode_plane: too big bytes %d", bytes));
271 s->p = holdp;
272 stream_write_uint8(s, 0); /* flags */
273 memcpy(s->p, plane, cx * cy);
274 s->p += cx * cy;
275 stream_write_uint8(s, 0); /* pad if not RLE */
276 bytes = cx * cy + 2;
277 }
278 else
279 {
280 LLOGLN(10, ("rfx_encode_plane: ok bytes %d", bytes));
281 }
282 return bytes;
283 }
284