I don't have the binary decoder, and this is as far as I got with pure guessing and only 2 samples. Intra frames seem to work, and full-block inter updates work as well. Partial/special coded blocks I could not figure out. Samples: http://samples.mplayerhq.hu/game-formats/la-san/jediknight-sith/ --- libavcodec/sanm.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-)
diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c index 1aa002b..2eb7e44 100644 --- a/libavcodec/sanm.c +++ b/libavcodec/sanm.c @@ -947,6 +947,158 @@ static int old_codec47(SANMVideoContext *ctx, int top, return 0; } +// Currently mostly a copy of old_codec47, but there might +// be further differences to be discovered. +static int old_codec48(SANMVideoContext *ctx, int top, + int left, int width, int height) +{ + uint32_t decoded_size; + int i, j; + int stride = ctx->pitch; + uint8_t *dst = (uint8_t *)ctx->frm0 + left + top * stride; + uint8_t *prev1 = (uint8_t *)ctx->frm1; + uint8_t *prev2 = (uint8_t *)ctx->frm2; + int tbl_pos = bytestream2_tell(&ctx->gb); + int skip; + int compr = bytestream2_get_byte(&ctx->gb); + int new_rot = bytestream2_get_byte(&ctx->gb); + int seq = bytestream2_get_le16(&ctx->gb); + // Not sure which is which... + decoded_size = bytestream2_get_le32(&ctx->gb); + decoded_size = bytestream2_get_le32(&ctx->gb); + skip = bytestream2_get_byte(&ctx->gb) >> 3; + bytestream2_get_le24(&ctx->gb); // unknown + + if (decoded_size > ctx->height * stride - left - top * stride) { + decoded_size = ctx->height * stride - left - top * stride; + av_log(ctx->avctx, AV_LOG_WARNING, "Decoded size is too large.\n"); + } + + if (skip & 1) + bytestream2_skip(&ctx->gb, 0x8080); + if (!seq) { + ctx->prev_seq = -1; + memset(prev1, 0, ctx->height * stride); + memset(prev2, 0, ctx->height * stride); + } + + switch (compr) { + case 0: + if (bytestream2_get_bytes_left(&ctx->gb) < width * height) + return AVERROR_INVALIDDATA; + for (j = 0; j < height; j++) { + bytestream2_get_bufferu(&ctx->gb, dst, width); + dst += stride; + } + break; + case 1: + if (bytestream2_get_bytes_left(&ctx->gb) < ((width + 1) >> 1) * ((height + 1) >> 1)) + return AVERROR_INVALIDDATA; + for (j = 0; j < height; j += 2) { + for (i = 0; i < width; i += 2) { + dst[i] = + dst[i + 1] = + dst[stride + i] = + dst[stride + i + 1] = bytestream2_get_byteu(&ctx->gb); + } + dst += stride * 2; + } + break; + case 2: + if (seq == ctx->prev_seq + 1) { + for (j = 0; j < height; j += 8) { + for (i = 0; i < width; i += 8) + if (process_block(ctx, dst + i, prev1 + i, prev2 + i, stride, + tbl_pos + 8, 8)) + return AVERROR_INVALIDDATA; + dst += stride * 8; + prev1 += stride * 8; + prev2 += stride * 8; + } + } + break; + case 3: + memcpy(ctx->frm0, ctx->frm2, ctx->pitch * ctx->height); + avpriv_report_missing_feature(ctx->avctx, + "Subcodec 48 compression 3 only partially supported"); + for (j = 0; j < height; j += 8) { + for (i = 0; i < width; i += 8) { + int k; + int b = bytestream2_get_byte(&ctx->gb); + if (b == 0) + continue; + // TODO: only 0xf7 decodes correctly, all others + // only have the correct input length + // 0xf9 and 0xf8 give approximately visually correct output + // for s4l3ocs.san but are absolutely not correct. + switch (b) { + case 0xfe: + bytestream2_get_buffer(&ctx->gb, dst + i, 2); + break; + case 0xfd: + bytestream2_get_buffer(&ctx->gb, dst + i, 4); + break; + case 0xfc: + bytestream2_get_buffer(&ctx->gb, dst + i, 4); + break; + case 0xfb: + bytestream2_get_buffer(&ctx->gb, dst + i, 8); + break; + case 0xf9: + for (k = 0; k < 8; k += 2) + { + uint8_t *d = dst + i + k * stride; + int l; + for (l = 0; l < 8; l += 2) { + uint8_t in = bytestream2_get_byte(&ctx->gb); + if (in) { d[l] = d[l + 1] = d[l + stride] = d[l + stride + 1] = 0x32; } + } + } + break; + case 0xf8: + for (k = 0; k < 8; k += 2) + { + uint8_t *d = dst + i + k * stride; + int l; + for (l = 0; l < 8; l++) { + uint8_t in = bytestream2_get_byte(&ctx->gb); + if (in >> 4) d[l] = 0x4b; + if (in & 0xf) d[l + stride] = 0x4b; + } + } + break; + case 0xf7: + for (k = 0; k < 8; k++) + bytestream2_get_buffer(&ctx->gb, dst + i + k * stride, 8); + break; + default: + break; + } + } + dst += stride * 8; + } + break; + case 4: + memcpy(ctx->frm0, ctx->frm1, ctx->pitch * ctx->height); + break; + case 5: + if (rle_decode(ctx, dst, decoded_size)) + return AVERROR_INVALIDDATA; + break; + default: + avpriv_report_missing_feature(ctx->avctx, + "Subcodec 48 compression %d", compr); + return AVERROR_PATCHWELCOME; + } + if (seq == ctx->prev_seq + 1) + ctx->rotate_code = new_rot; + else + ctx->rotate_code = 0; + ctx->prev_seq = seq; + + return 0; +} + static int process_frame_obj(SANMVideoContext *ctx) { uint16_t codec = bytestream2_get_le16u(&ctx->gb); @@ -985,8 +1137,10 @@ static int process_frame_obj(SANMVideoContext *ctx) case 47: return old_codec47(ctx, top, left, w, h); break; + case 48: + return old_codec48(ctx, top, left, w, h); default: - avpriv_request_sample(ctx->avctx, "Subcodec %d", codec); + avpriv_request_sample(ctx->avctx, "Subcodec %d fobj", codec); return AVERROR_PATCHWELCOME; } } -- 2.7.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel