This codec works on 4x4 pixel tiles, which can be generated and read from the datastream. They're both identical, codec5 misses a tile index to skip the current tile. Codecs33/34 are the same as 4/5 but with a different tileset generator. Used only in Rebel Assault 1.
Unified · Split
| @@ -293,6 +293,8 @@ typedef struct SANMVideoContext { · 292 unmodified lines | |||
| 293 | int8_t p8x8glyphs[NGLYPHS][64]; | 293 | int8_t p8x8glyphs[NGLYPHS][64]; |
| 294 | uint8_t c47itbl[0x10000]; | 294 | uint8_t c47itbl[0x10000]; |
| 295 | uint8_t c23lut[256]; | 295 | uint8_t c23lut[256]; |
| 296 | uint8_t c4tbl[2][256][16]; | ||
| 297 | uint16_t c4param; | ||
| 296 | } SANMVideoContext; | 298 | } SANMVideoContext; |
| 297 | 299 | ||
| 298 | typedef struct SANMFrameHeader { | 300 | typedef struct SANMFrameHeader { |
| @@ -480,6 +482,142 @@ static av_cold int init_buffers(SANMVideoContext *ctx) · 181 unmodified lines | |||
| 480 | return 0; | 482 | return 0; |
| 481 | } | 483 | } |
| 482 | 484 | ||
| 485 | static void codec33_gen_tiles(SANMVideoContext *ctx, int8_t param1) | ||
| 486 | { | ||
| 487 | uint8_t *dst = &(ctx->c4tbl[0][0][0]); | ||
| 488 | int i, j, k, l, m, n, o, p; | ||
| 489 | |||
| 490 | for (i = 0; i < 8; i++) { | ||
| 491 | for (k = 0; k < 8; k++) { | ||
| 492 | j = i + param1; | ||
| 493 | l = k + param1; | ||
| 494 | p = (j + k) / 2; | ||
| 495 | j = (j + p) / 2; | ||
| 496 | m = l / 2; | ||
| 497 | n = (i + param1); | ||
| 498 | o = (k + param1); | ||
| 499 | |||
| 500 | *dst++ = p; *dst++ = p; *dst++ = j; *dst++ = n; | ||
| 501 | *dst++ = p; *dst++ = p; *dst++ = j; *dst++ = i; | ||
| 502 | *dst++ = m; *dst++ = m; *dst++ = p; *dst++ = j; | ||
| 503 | *dst++ = l; *dst++ = l; *dst++ = m; *dst++ = p; | ||
| 504 | } | ||
| 505 | } | ||
| 506 | |||
| 507 | for (i = 0; i < 8; i++) { | ||
| 508 | for (k = 0; k < 8; k++) { | ||
| 509 | j = i + param1; | ||
| 510 | l = k + param1; | ||
| 511 | n = ((j + l) / 2); | ||
| 512 | m = ((l + n) / 2); | ||
| 513 | |||
| 514 | *dst++ = j; *dst++ = j; *dst++ = j; *dst++ = j; | ||
| 515 | *dst++ = n; *dst++ = n; *dst++ = n; *dst++ = n; | ||
| 516 | *dst++ = m; *dst++ = m; *dst++ = m; *dst++ = m; | ||
| 517 | *dst++ = l; *dst++ = l; *dst++ = l; *dst++ = l; | ||
| 518 | } | ||
| 519 | } | ||
| 520 | |||
| 521 | for (i = 0; i < 8; i++) { | ||
| 522 | for (k = 0; k < 8; k++) { | ||
| 523 | j = i + param1; | ||
| 524 | l = k + param1; | ||
| 525 | m = (j + l) / 2; | ||
| 526 | n = (j + m) / 2; | ||
| 527 | o = m / 2; | ||
| 528 | p = j & 0xff; | ||
| 529 | |||
| 530 | *dst++ = p; *dst++ = p; *dst++ = n; *dst++ = m; | ||
| 531 | *dst++ = p; *dst++ = p; *dst++ = n; *dst++ = m; | ||
| 532 | *dst++ = n; *dst++ = n; *dst++ = m; *dst++ = o; | ||
| 533 | *dst++ = m; *dst++ = m; *dst++ = o; *dst++ = l; | ||
| 534 | } | ||
| 535 | } | ||
| 536 | |||
| 537 | for (i = 0; i < 8; i++) { | ||
| 538 | for (k = 0; k < 8; k++) { | ||
| 539 | j = i + param1; | ||
| 540 | l = k + param1; | ||
| 541 | m = (j + l) / 2; | ||
| 542 | n = m / 2; | ||
| 543 | |||
| 544 | *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; | ||
| 545 | *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; | ||
| 546 | *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; | ||
| 547 | *dst++ = j; *dst++ = m; *dst++ = n; *dst++ = l; | ||
| 548 | } | ||
| 549 | } | ||
| 550 | } | ||
| 551 | |||
| 552 | static void codec4_gen_tiles(SANMVideoContext *ctx, uint16_t param1) | ||
| 553 | { | ||
| 554 | uint8_t *dst = &(ctx->c4tbl[0][0][0]); | ||
| 555 | int i, j, k, l, m, n, o; | ||
| 556 | |||
| 557 | for (i = 1; i < 16; i += 2) { | ||
| 558 | for (k = 0; k < 16; k++) { | ||
| 559 | j = i + param1; | ||
| 560 | l = k + param1; | ||
| 561 | m = (j + l) / 2; | ||
| 562 | n = (j + m) / 2; | ||
| 563 | o = (l + m) / 2; | ||
| 564 | if (j == m || l == m) { | ||
| 565 | *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = j; | ||
| 566 | *dst++ = j; *dst++ = l; *dst++ = j; *dst++ = j; | ||
| 567 | *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = j; | ||
| 568 | *dst++ = l; *dst++ = l; *dst++ = j; *dst++ = l; | ||
| 569 | } else { | ||
| 570 | *dst++ = m; *dst++ = m; *dst++ = n; *dst++ = j; | ||
| 571 | *dst++ = m; *dst++ = m; *dst++ = n; *dst++ = j; | ||
| 572 | *dst++ = o; *dst++ = o; *dst++ = m; *dst++ = n; | ||
| 573 | *dst++ = l; *dst++ = l; *dst++ = o; *dst++ = m; | ||
| 574 | } | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | for (i = 0; i < 16; i += 2) { | ||
| 579 | for (k = 0; k < 16; k++) { | ||
| 580 | j = i + param1; | ||
| 581 | l = k + param1; | ||
| 582 | m = (j + l) / 2; | ||
| 583 | n = (j + m) / 2; | ||
| 584 | o = (l + m) / 2; | ||
| 585 | if (m == j || m == l) { | ||
| 586 | *dst++ = j; *dst++ = j; *dst++ = l; *dst++ = j; | ||
| 587 | *dst++ = j; *dst++ = j; *dst++ = j; *dst++ = l; | ||
| 588 | *dst++ = l; *dst++ = j; *dst++ = l; *dst++ = l; | ||
| 589 | *dst++ = j; *dst++ = l; *dst++ = j; *dst++ = l; | ||
| 590 | } else { | ||
| 591 | *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; | ||
| 592 | *dst++ = j; *dst++ = j; *dst++ = n; *dst++ = m; | ||
| 593 | *dst++ = n; *dst++ = n; *dst++ = m; *dst++ = o; | ||
| 594 | *dst++ = m; *dst++ = m; *dst++ = o; *dst++ = l; | ||
| 595 | } | ||
| 596 | } | ||
| 597 | } | ||
| 598 | } | ||
| 599 | |||
| 600 | |||
| 601 | static int codec4_load_tiles(SANMVideoContext *ctx, uint16_t param2, uint8_t clr) | ||
| 602 | { | ||
| 603 | uint8_t c, *dst = (uint8_t *)&(ctx->c4tbl[1][0][0]); | ||
| 604 | uint32_t loop = param2 * 8; | ||
| 605 | |||
| 606 | if (param2 > 256) | ||
| 607 | return AVERROR_INVALIDDATA; | ||
| 608 | |||
| 609 | if (bytestream2_get_bytes_left(&ctx->gb) < loop) | ||
| 610 | return AVERROR_INVALIDDATA; | ||
| 611 | |||
| 612 | while (loop--) { | ||
| 613 | c = bytestream2_get_byteu(&ctx->gb); | ||
| 614 | *dst++ = (c >> 4) + clr; | ||
| 615 | *dst++ = (c & 0xf) + clr; | ||
| 616 | } | ||
| 617 | |||
| 618 | return 0; | ||
| 619 | } | ||
| 620 | |||
| 483 | static void rotate_bufs(SANMVideoContext *ctx, int rotate_code) | 621 | static void rotate_bufs(SANMVideoContext *ctx, int rotate_code) |
| 484 | { | 622 | { |
| 485 | if (rotate_code == 2) | 623 | if (rotate_code == 2) |
| @@ -519,6 +657,7 @@ static av_cold int decode_init(AVCodecContext *avctx) · 33 unmodified lines | |||
| 519 | if (ctx->subversion < 2) | 657 | if (ctx->subversion < 2) |
| 520 | ctx->pal[0] = 0xFFU << 24; | 658 | ctx->pal[0] = 0xFFU << 24; |
| 521 | } | 659 | } |
| 660 | ctx->c4param = 0xffff; | ||
| 522 | 661 | ||
| 523 | return 0; | 662 | return 0; |
| 524 | } | 663 | } |
| @@ -532,6 +671,91 @@ static av_cold int decode_end(AVCodecContext *avctx) · 7 unmodified lines | |||
| 532 | return 0; | 671 | return 0; |
| 533 | } | 672 | } |
| 534 | 673 | ||
| 674 | static int old_codec4(SANMVideoContext *ctx, int top, int left, int w, int h, | ||
| 675 | uint8_t param, uint16_t param2, int codec) | ||
| 676 | { | ||
| 677 | const uint16_t p = ctx->pitch; | ||
| 678 | const uint32_t maxpxo = ctx->height * p; | ||
| 679 | uint8_t mask, bits, idx, *gs, *dst = (uint8_t *)ctx->frm0; | ||
| 680 | int i, j, k, l, bit, ret; | ||
| 681 | int32_t pxoff, pxo2; | ||
| 682 | |||
| 683 | if (ctx->c4param != param) { | ||
| 684 | if (codec > 32) | ||
| 685 | codec33_gen_tiles(ctx, param); | ||
| 686 | else | ||
| 687 | codec4_gen_tiles(ctx, param); | ||
| 688 | ctx->c4param = param; | ||
| 689 | } | ||
| 690 | if (param2 > 0) { | ||
| 691 | ret = codec4_load_tiles(ctx, param2, param); | ||
| 692 | if (ret) | ||
| 693 | return ret; | ||
| 694 | } | ||
| 695 | |||
| 696 | if (codec > 32) | ||
| 697 | codec -= 29; | ||
| 698 | |||
| 699 | for (j = 0; j < w; j += 4) { | ||
| 700 | mask = bits = 0; | ||
| 701 | for (i = 0; i < h; i += 4) { | ||
| 702 | pxoff = j + left + ((top + i) * p); | ||
| 703 | if (param2 > 0) { | ||
| 704 | if (bits == 0) { | ||
| 705 | if (bytestream2_get_bytes_left(&ctx->gb) < 1) | ||
| 706 | return AVERROR_INVALIDDATA; | ||
| 707 | mask = bytestream2_get_byteu(&ctx->gb); | ||
| 708 | bits = 8; | ||
| 709 | } | ||
| 710 | bit = !!(mask & 0x80); | ||
| 711 | mask <<= 1; | ||
| 712 | bits--; | ||
| 713 | } else { | ||
| 714 | bit = 0; | ||
| 715 | } | ||
| 716 | |||
| 717 | if (bytestream2_get_bytes_left(&ctx->gb) < 1) | ||
| 718 | return AVERROR_INVALIDDATA; | ||
| 719 | idx = bytestream2_get_byteu(&ctx->gb); | ||
| 720 | if ((bit == 0) && (idx == 0x80) && (codec != 5)) | ||
| 721 | continue; | ||
| 722 | |||
| 723 | gs = &(ctx->c4tbl[bit][idx][0]); | ||
| 724 | pxo2 = pxoff; | ||
| 725 | for (k = 0; k < 4; k++) { | ||
| 726 | for (l = 0; l < 4; l++) { | ||
| 727 | if (pxo2 >= 0 && pxo2 < maxpxo) { | ||
| 728 | *(dst + pxo2) = *gs; | ||
| 729 | } | ||
| 730 | gs++; | ||
| 731 | pxo2++; | ||
| 732 | } | ||
| 733 | pxo2 = pxo2 - 4 + p; | ||
| 734 | } | ||
| 735 | |||
| 736 | /* smooth top and left block borders with neighbours */ | ||
| 737 | if (((pxoff - p + k) < 0) || ((pxoff - p + k) >= maxpxo) | ||
| 738 | || ((pxoff + 3 * p) < 0) || ((pxoff + 3 * p) >= maxpxo) | ||
| 739 | || (i == 0) || (j == 0)) | ||
| 740 | continue; | ||
| 741 | if (param & 0x80) { | ||
| 742 | for (k = 0; k < 4; k++) | ||
| 743 | *(dst + pxoff + k) = ((*(dst + pxoff + k) + *(dst + pxoff - p + k)) >> 1) | 0x80; | ||
| 744 | *(dst + pxoff + 1 * p) = (*(dst + pxoff + 1 * p) + *(dst + pxoff + 1 * p - 1)) >> 1 | 0x80; | ||
| 745 | *(dst + pxoff + 2 * p) = (*(dst + pxoff + 2 * p) + *(dst + pxoff + 2 * p - 1)) >> 1 | 0x80; | ||
| 746 | *(dst + pxoff + 3 * p) = (*(dst + pxoff + 3 * p) + *(dst + pxoff + 3 * p - 1)) >> 1 | 0x80; | ||
| 747 | } else { | ||
| 748 | for (k = 0; k < 4; k++) | ||
| 749 | *(dst + pxoff + k) = ((*(dst + pxoff + k) + *(dst + pxoff - p + k)) >> 1) & 0x7f; | ||
| 750 | *(dst + pxoff + 1 * p) = (*(dst + pxoff + 1 * p) + *(dst + pxoff + 1 * p - 1)) >> 1; | ||
| 751 | *(dst + pxoff + 2 * p) = (*(dst + pxoff + 2 * p) + *(dst + pxoff + 2 * p - 1)) >> 1; | ||
| 752 | *(dst + pxoff + 3 * p) = (*(dst + pxoff + 3 * p) + *(dst + pxoff + 3 * p - 1)) >> 1; | ||
| 753 | } | ||
| 754 | } | ||
| 755 | } | ||
| 756 | return 0; | ||
| 757 | } | ||
| 758 | |||
| 535 | static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size) | 759 | static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size) |
| 536 | { | 760 | { |
| 537 | int opcode, color, run_len, left = out_size; | 761 | int opcode, color, run_len, left = out_size; |
| @@ -1436,6 +1660,11 @@ static int process_frame_obj(SANMVideoContext *ctx) · 898 unmodified lines | |||
| 1436 | return old_codec1(ctx, top, left, w, h, codec == 3); | 1660 | return old_codec1(ctx, top, left, w, h, codec == 3); |
| 1437 | case 2: | 1661 | case 2: |
| 1438 | return old_codec2(ctx, top, left, w, h); | 1662 | return old_codec2(ctx, top, left, w, h); |
| 1663 | case 4: | ||
| 1664 | case 5: | ||
| 1665 | case 33: | ||
| 1666 | case 34: | ||
| 1667 | return old_codec4(ctx, top, left, w, h, param, parm2, codec); | ||
| 1439 | case 21: | 1668 | case 21: |
| 1440 | return old_codec21(ctx, top, left, w, h); | 1669 | return old_codec21(ctx, top, left, w, h); |
| 1441 | case 23: | 1670 | case 23: |