| 183 | case 12: |
| 184 | |
| 185 | { |
| 186 | |
| 187 | uLong outsize1 = _width * _height; |
| 188 | uLong outsize2 = outsize1; |
| 189 | uLong outsize3 = outsize1*2; |
| 190 | uLong outsize4 = outsize1; |
| 191 | uLong outsize; |
| 192 | uint8 *outbuf; |
| 193 | uint8 *outbuf1 = new uint8[outsize1]; |
| 194 | uint8 *outbuf2 = new uint8[outsize2]; |
| 195 | uint8 *outbuf3 = new uint8[outsize3]; |
| 196 | uint8 *outbuf4 = new uint8[outsize4]; |
| 197 | uint8 *xorbuf = new uint8[_width * _height]; |
| 198 | |
| 199 | for (int i = 0; i < _width * _height; i++) |
| 200 | xorbuf[i] = _prevframe[i] ^ frame[i]; |
| 201 | |
| 202 | compress2(outbuf1, &outsize1, xorbuf, _width * _height, 9); |
| 203 | compress2(outbuf2, &outsize2, frame, _width * _height, 9); |
| 204 | if (outsize1 < outsize2) { |
| 205 | compType = 3; |
| 206 | outsize = outsize1; |
| 207 | outbuf = outbuf1; |
| 208 | } else { |
| 209 | compType = 2; |
| 210 | outsize = outsize2; |
| 211 | outbuf = outbuf2; |
| 212 | } |
| 213 | |
| 214 | outsize3 = m12encode(frame, outbuf3); |
| 215 | |
| 216 | compress2(outbuf4, &outsize4, outbuf3, outsize3, 9); |
| 217 | |
| 218 | if (outsize4 < outsize) { |
| 219 | compType = 12; |
| 220 | outsize = outsize4; |
| 221 | outbuf = outbuf4; |
| 222 | } |
| 223 | |
| 224 | writeByte(_dxa, compType); |
| 225 | writeUint32BE(_dxa, outsize); |
| 226 | fwrite(outbuf, outsize, 1, _dxa); |
| 227 | |
| 228 | delete[] outbuf1; |
| 229 | delete[] outbuf2; |
| 230 | delete[] outbuf3; |
| 231 | delete[] outbuf4; |
| 232 | delete[] xorbuf; |
| 233 | |
| 234 | break; |
| 235 | } |
| 247 | bool DxaEncoder::m12blocksAreEqual(byte *frame, int x, int y, int x2, int y2) { |
| 248 | byte *b1 = _prevframe + x + y * _width; |
| 249 | byte *b2 = frame + x2 + y2 * _width; |
| 250 | for (int yc = 0; yc < BLOCKH; yc++) { |
| 251 | if (memcmp(b1, b2, BLOCKW)) |
| 252 | return false; |
| 253 | b1 += _width; |
| 254 | b2 += _width; |
| 255 | } |
| 256 | return true; |
| 257 | } |
| 258 | |
| 259 | bool DxaEncoder::m12blockIsSolidColor(byte *frame, int x, int y, byte &color) { |
| 260 | byte *b2 = frame + x + y * _width; |
| 261 | color = *b2; |
| 262 | for (int yc = 0; yc < BLOCKH; yc++) { |
| 263 | for (int xc = 0; xc < BLOCKW; xc++) { |
| 264 | if (b2[xc] != color) |
| 265 | return false; |
| 266 | } |
| 267 | b2 += _width; |
| 268 | } |
| 269 | return true; |
| 270 | } |
| 271 | |
| 272 | void DxaEncoder::m12blockDelta(byte *frame, int x, int y, unsigned short &diffMap, int &diffCount, byte diffPix[]) { |
| 273 | byte *b1 = _prevframe + x + y * _width; |
| 274 | byte *b2 = frame + x + y * _width; |
| 275 | diffCount = 0; |
| 276 | diffMap = 0; |
| 277 | for (int yc = 0; yc < BLOCKH; yc++) { |
| 278 | for (int xc = 0; xc < BLOCKW; xc++) { |
| 279 | if (b1[xc] != b2[xc]) { |
| 280 | diffMap = (diffMap << 1) | 1; |
| 281 | diffPix[diffCount++] = b2[xc]; |
| 282 | } else { |
| 283 | diffMap = (diffMap << 1) | 0; |
| 284 | } |
| 285 | } |
| 286 | b1 += _width; |
| 287 | b2 += _width; |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | bool DxaEncoder::m12motionVector(byte *frame, int x, int y, int &mx, int &my) { |
| 292 | int xmin = (0 > x-7) ? 0 : x-7; |
| 293 | int ymin = (0 > y-7) ? 0 : y-7; |
| 294 | int xmax = (_width < x+8) ? _width : x+8; |
| 295 | int ymax = (_height < y+8) ? _height : y+8; |
| 296 | for (int yc = ymin; yc < ymax; yc++) { |
| 297 | for (int xc = xmin; xc < xmax; xc++) { |
| 298 | if (m12blocksAreEqual(frame, xc, yc, x, y)) { |
| 299 | mx = xc - x; |
| 300 | my = yc - y; |
| 301 | return true; |
| 302 | } |
| 303 | } |
| 304 | } |
| 305 | return false; |
| 306 | } |
| 307 | |
| 308 | uLong DxaEncoder::m12encode(byte *frame, byte *outbuf) { |
| 309 | byte *outb = outbuf; |
| 310 | byte color; |
| 311 | int mx, my; |
| 312 | unsigned short diffMap; |
| 313 | int diffCount; |
| 314 | byte diffPix[BLOCKW*BLOCKH]; |
| 315 | |
| 316 | for (int by = 0; by < _height; by += BLOCKH) { |
| 317 | for (int bx = 0; bx < _width; bx += BLOCKW) { |
| 318 | if (m12blocksAreEqual(frame, bx, by, bx, by)) { |
| 319 | *outb++ = 0; |
| 320 | continue; |
| 321 | } |
| 322 | |
| 323 | if (m12blockIsSolidColor(frame, bx, by, color)) { |
| 324 | *outb++ = 2; |
| 325 | *outb++ = color; |
| 326 | continue; |
| 327 | } |
| 328 | |
| 329 | if (m12motionVector(frame, bx, by, mx, my)) { |
| 330 | byte mbyte = 0; |
| 331 | if (mx < 0) mbyte |= 0x80; |
| 332 | mbyte |= (abs(mx) & 7) << 4; |
| 333 | if (my < 0) mbyte |= 0x08; |
| 334 | mbyte |= abs(my) & 7; |
| 335 | *outb++ = 4; |
| 336 | *outb++ = mbyte; |
| 337 | continue; |
| 338 | } |
| 339 | |
| 340 | m12blockDelta(frame, bx, by, diffMap, diffCount, diffPix); |
| 341 | |
| 342 | if (diffCount >= 14) { |
| 343 | // in this case we store all 16 pixels |
| 344 | *outb++ = 3; |
| 345 | byte *b2 = (byte*)frame + bx + by * _width; |
| 346 | for (int yc = 0; yc < BLOCKH; yc++) { |
| 347 | memcpy(outb, b2, BLOCKW); |
| 348 | b2 += _width; |
| 349 | outb += BLOCKW; |
| 350 | } |
| 351 | continue; |
| 352 | } else { |
| 353 | static const struct { uint16 mask; uint8 sh1, sh2; } maskTbl[6] = { |
| 354 | {0xFF00, 0, 0}, |
| 355 | {0x0FF0, 8, 0}, |
| 356 | {0x00FF, 8, 8}, |
| 357 | {0x0F0F, 8, 4}, |
| 358 | {0xF0F0, 4, 0}, |
| 359 | {0xF00F, 4, 4} |
| 360 | }; |
| 361 | |
| 362 | bool smallMask = false; |
| 363 | |
| 364 | // here we check if the difference bitmap can be stored in only one byte |
| 365 | for (int m = 0; m < 6; m++) { |
| 366 | if ((diffMap & maskTbl[m].mask) == 0) { |
| 367 | smallMask = true; |
| 368 | *outb++ = 10 + m; |
| 369 | *outb++ = ((diffMap >> maskTbl[m].sh1) & 0xF0) | ((diffMap >> maskTbl[m].sh2) & 0x0F); |
| 370 | break; |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | if (!smallMask) { |
| 375 | *outb++ = 1; |
| 376 | *(unsigned short*)outb = diffMap; |
| 377 | outb += 2; |
| 378 | } |
| 379 | |
| 380 | memcpy(outb, diffPix, diffCount); |
| 381 | outb += diffCount; |
| 382 | continue; |
| 383 | } |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | return outb - outbuf; |
| 388 | } |
| 389 | |