History

avcodec/sanm: codec4/5/33/34 decoder

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.

Manuel Lauss committed 1 year ago

Commit fb951b21 parent e1fd6bc1 file · +229 −0Browse files

Showing the changes to libavcodec (1 of 1 file). Show all

Unified · Split

libavcodec/sanm.c+229−0
@@ -293,6 +293,8 @@ typedef struct SANMVideoContext { · 292 unmodified lines
293293 int8_t p8x8glyphs[NGLYPHS][64];
294294 uint8_t c47itbl[0x10000];
295295 uint8_t c23lut[256];
296+ uint8_t c4tbl[2][256][16];
297+ uint16_t c4param;
296298 } SANMVideoContext;
297299
298300 typedef struct SANMFrameHeader {
@@ -480,6 +482,142 @@ static av_cold int init_buffers(SANMVideoContext *ctx) · 181 unmodified lines
480482 return 0;
481483 }
482484
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+
483621 static void rotate_bufs(SANMVideoContext *ctx, int rotate_code)
484622 {
485623 if (rotate_code == 2)
@@ -519,6 +657,7 @@ static av_cold int decode_init(AVCodecContext *avctx) · 33 unmodified lines
519657 if (ctx->subversion < 2)
520658 ctx->pal[0] = 0xFFU << 24;
521659 }
660+ ctx->c4param = 0xffff;
522661
523662 return 0;
524663 }
@@ -532,6 +671,91 @@ static av_cold int decode_end(AVCodecContext *avctx) · 7 unmodified lines
532671 return 0;
533672 }
534673
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+
535759 static int rle_decode(SANMVideoContext *ctx, uint8_t *dst, const int out_size)
536760 {
537761 int opcode, color, run_len, left = out_size;
@@ -1436,6 +1660,11 @@ static int process_frame_obj(SANMVideoContext *ctx) · 898 unmodified lines
14361660 return old_codec1(ctx, top, left, w, h, codec == 3);
14371661 case 2:
14381662 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);
14391668 case 21:
14401669 return old_codec21(ctx, top, left, w, h);
14411670 case 23:

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t