| 237 | case 12: |
| 238 | |
| 239 | { |
| 240 | |
| 241 | uLong outsize1 = _width * _height; |
| 242 | uLong outsize2 = outsize1; |
| 243 | uLong outsize3 = outsize1*2; |
| 244 | uLong outsize4 = outsize1; |
| 245 | uLong outsize; |
| 246 | uint8 *outbuf; |
| 247 | uint8 *outbuf1 = new uint8[outsize1]; |
| 248 | uint8 *outbuf2 = new uint8[outsize2]; |
| 249 | uint8 *outbuf3 = new uint8[outsize3]; |
| 250 | uint8 *outbuf4 = new uint8[outsize4]; |
| 251 | uint8 *xorbuf = new uint8[_width * _height]; |
| 252 | |
| 253 | for (int i = 0; i < _width * _height; i++) |
| 254 | xorbuf[i] = _prevframe[i] ^ frame[i]; |
| 255 | |
| 256 | compress2(outbuf1, &outsize1, xorbuf, _width * _height, 9); |
| 257 | compress2(outbuf2, &outsize2, frame, _width * _height, 9); |
| 258 | if (outsize1 < outsize2) { |
| 259 | compType = 3; |
| 260 | outsize = outsize1; |
| 261 | outbuf = outbuf1; |
| 262 | } else { |
| 263 | compType = 2; |
| 264 | outsize = outsize2; |
| 265 | outbuf = outbuf2; |
| 266 | } |
| 267 | |
| 268 | outsize3 = m12encode(frame, outbuf3); |
| 269 | |
| 270 | compress2(outbuf4, &outsize4, outbuf3, outsize3, 9); |
| 271 | |
| 272 | if (outsize4 < outsize) { |
| 273 | compType = 12; |
| 274 | outsize = outsize4; |
| 275 | outbuf = outbuf4; |
| 276 | } |
| 277 | |
| 278 | writeByte(_dxa, compType); |
| 279 | writeUint32BE(_dxa, outsize); |
| 280 | fwrite(outbuf, outsize, 1, _dxa); |
| 281 | |
| 282 | delete[] outbuf1; |
| 283 | delete[] outbuf2; |
| 284 | delete[] outbuf3; |
| 285 | delete[] outbuf4; |
| 286 | delete[] xorbuf; |
| 287 | |
| 288 | break; |
| 289 | } |
| 301 | bool DxaEncoder::m12blocksAreEqual(byte *frame, int x, int y, int x2, int y2) { |
| 302 | byte *b1 = _prevframe + x + y * _width; |
| 303 | byte *b2 = frame + x2 + y2 * _width; |
| 304 | for (int yc = 0; yc < BLOCKH; yc++) { |
| 305 | if(memcmp(b1, b2, BLOCKW)) |
| 306 | return false; |
| 307 | b1 += _width; |
| 308 | b2 += _width; |
| 309 | } |
| 310 | return true; |
| 311 | } |
| 312 | |
| 313 | bool DxaEncoder::m12blockIsSolidColor(byte *frame, int x, int y, byte &color) { |
| 314 | byte *b2 = frame + x + y * _width; |
| 315 | color = *b2; |
| 316 | for (int yc = 0; yc < BLOCKH; yc++) { |
| 317 | for (int xc = 0; xc < BLOCKW; xc++) { |
| 318 | if (b2[xc] != color) |
| 319 | return false; |
| 320 | } |
| 321 | b2 += _width; |
| 322 | } |
| 323 | return true; |
| 324 | } |
| 325 | |
| 326 | void DxaEncoder::m12blockDelta(byte *frame, int x, int y, unsigned short &diffMap, int &diffCount, byte diffPix[]) { |
| 327 | byte *b1 = _prevframe + x + y * _width; |
| 328 | byte *b2 = frame + x + y * _width; |
| 329 | diffCount = 0; |
| 330 | diffMap = 0; |
| 331 | for (int yc = 0; yc < BLOCKH; yc++) { |
| 332 | for (int xc = 0; xc < BLOCKW; xc++) { |
| 333 | if (b1[xc] != b2[xc]) |
| 334 | { |
| 335 | diffMap = (diffMap << 1) | 1; |
| 336 | diffPix[diffCount++] = b2[xc]; |
| 337 | } else { |
| 338 | diffMap = (diffMap << 1) | 0; |
| 339 | } |
| 340 | } |
| 341 | b1 += _width; |
| 342 | b2 += _width; |
| 343 | } |
| 344 | } |
| 345 | |
| 346 | bool DxaEncoder::m12motionVector(byte *frame, int x, int y, int &mx, int &my) { |
| 347 | int xmin = (0 > x-7) ? 0 : x-7; |
| 348 | int ymin = (0 > y-7) ? 0 : y-7; |
| 349 | int xmax = (_width < x+8) ? _width : x+8; |
| 350 | int ymax = (_height < y+8) ? _height : y+8; |
| 351 | for (int yc = ymin; yc < ymax; yc++) { |
| 352 | for (int xc = xmin; xc < xmax; xc++) { |
| 353 | if (m12blocksAreEqual(frame, xc, yc, x, y)) { |
| 354 | mx = xc - x; |
| 355 | my = yc - y; |
| 356 | return true; |
| 357 | } |
| 358 | } |
| 359 | } |
| 360 | return false; |
| 361 | } |
| 362 | |
| 363 | uLong DxaEncoder::m12encode(byte *frame, byte *outbuf) { |
| 364 | |
| 365 | byte *outb = outbuf; |
| 366 | |
| 367 | byte color; |
| 368 | int mx, my; |
| 369 | unsigned short diffMap; |
| 370 | int diffCount; |
| 371 | byte diffPix[BLOCKW*BLOCKH]; |
| 372 | |
| 373 | int curBlock = 0; |
| 374 | |
| 375 | for (int by = 0; by < _height; by += BLOCKH) { |
| 376 | for (int bx = 0; bx < _width; bx += BLOCKW) { |
| 377 | |
| 378 | if (m12blocksAreEqual(frame, bx, by, bx, by)) { |
| 379 | *outb++ = 0; |
| 380 | continue; |
| 381 | } |
| 382 | |
| 383 | if (m12blockIsSolidColor(frame, bx, by, color)) { |
| 384 | *outb++ = 2; |
| 385 | *outb++ = color; |
| 386 | continue; |
| 387 | } |
| 388 | |
| 389 | if (m12motionVector(frame, bx, by, mx, my)) { |
| 390 | byte mbyte = 0; |
| 391 | if (mx < 0) mbyte |= 0x80; |
| 392 | mbyte |= (abs(mx) & 7) << 4; |
| 393 | if (my < 0) mbyte |= 0x08; |
| 394 | mbyte |= abs(my) & 7; |
| 395 | *outb++ = 4; |
| 396 | *outb++ = mbyte; |
| 397 | continue; |
| 398 | } |
| 399 | |
| 400 | m12blockDelta(frame, bx, by, diffMap, diffCount, diffPix); |
| 401 | |
| 402 | if (diffCount >= 14) { |
| 403 | // in this case we store all 16 pixels |
| 404 | *outb++ = 3; |
| 405 | byte *b2 = (byte*)frame + bx + by * _width; |
| 406 | for (int yc = 0; yc < BLOCKH; yc++) { |
| 407 | memcpy(outb, b2, BLOCKW); |
| 408 | b2 += _width; |
| 409 | outb += BLOCKW; |
| 410 | } |
| 411 | continue; |
| 412 | } else { |
| 413 | |
| 414 | static const struct { uint16 mask; uint8 sh1, sh2; } maskTbl[6] = { |
| 415 | {0xFF00, 0, 0}, |
| 416 | {0x0FF0, 8, 0}, |
| 417 | {0x00FF, 8, 8}, |
| 418 | {0x0F0F, 8, 4}, |
| 419 | {0xF0F0, 4, 0}, |
| 420 | {0xF00F, 4, 4} |
| 421 | }; |
| 422 | |
| 423 | bool smallMask = false; |
| 424 | |
| 425 | // here we check if the difference bitmap can be stored in only one byte |
| 426 | for (int m = 0; m < 6; m++) { |
| 427 | if ((diffMap & maskTbl[m].mask) == 0) { |
| 428 | smallMask = true; |
| 429 | *outb++ = 10 + m; |
| 430 | *outb++ = ((diffMap >> maskTbl[m].sh1) & 0xF0) | ((diffMap >> maskTbl[m].sh2) & 0x0F); |
| 431 | break; |
| 432 | } |
| 433 | } |
| 434 | |
| 435 | if (!smallMask) { |
| 436 | *outb++ = 1; |
| 437 | *(unsigned short*)outb = diffMap; |
| 438 | outb += 2; |
| 439 | } |
| 440 | |
| 441 | memcpy(outb, diffPix, diffCount); |
| 442 | outb += diffCount; |
| 443 | continue; |
| 444 | } |
| 445 | |
| 446 | } |
| 447 | } |
| 448 | |
| 449 | return outb - outbuf; |
| 450 | } |
| 451 | |