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.
Showing the changes to libavcodec (1 of 1 file). Show all
Unified · Split
| @@ -293,6 +293,8 @@ typedef struct SANMVideoContext { · 292 unmodified lines | ||
| 293 | 293 | int8_t p8x8glyphs[NGLYPHS][64]; |
| 294 | 294 | uint8_t c47itbl[0x10000]; |
| 295 | 295 | uint8_t c23lut[256]; |
| 296 | + uint8_t c4tbl[2][256][16]; | |
| 297 | + uint16_t c4param; | |
| 296 | 298 | } SANMVideoContext; |
| 297 | 299 | |
| 298 | 300 | typedef struct SANMFrameHeader { |
| @@ -480,6 +482,142 @@ static av_cold int init_buffers(SANMVideoContext *ctx) · 181 unmodified lines | ||
| 480 | 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 | 621 | static void rotate_bufs(SANMVideoContext *ctx, int rotate_code) |
| 484 | 622 | { |
| 485 | 623 | if (rotate_code == 2) |
| @@ -519,6 +657,7 @@ static av_cold int decode_init(AVCodecContext *avctx) · 33 unmodified lines | ||
| 519 | 657 | if (ctx->subversion < 2) |
| 520 | 658 | ctx->pal[0] = 0xFFU << 24; |
| 521 | 659 | } |
| 660 | + ctx->c4param = 0xffff; | |
| 522 | 661 | |
| 523 | 662 | return 0; |
| 524 | 663 | } |
| @@ -532,6 +671,91 @@ static av_cold int decode_end(AVCodecContext *avctx) · 7 unmodified lines | ||
| 532 | 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 | 759 | static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size) |
| 536 | 760 | { |
| 537 | 761 | int opcode, color, run_len, left = out_size; |
| @@ -1436,6 +1660,11 @@ static int process_frame_obj(SANMVideoContext *ctx) · 898 unmodified lines | ||
| 1436 | 1660 | return old_codec1(ctx, top, left, w, h, codec == 3); |
| 1437 | 1661 | case 2: |
| 1438 | 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 | 1668 | case 21: |
| 1440 | 1669 | return old_codec21(ctx, top, left, w, h); |
| 1441 | 1670 | case 23: |