|
|
|
@@ -30,7 +30,15 @@ |
|
|
|
#include "common.h" |
|
|
|
#include "avcodec.h" |
|
|
|
|
|
|
|
#define MAGIC_WMVi 0x574D5669 |
|
|
|
enum EncTypes { |
|
|
|
MAGIC_WMVd = 0x574D5664, |
|
|
|
MAGIC_WMVe, |
|
|
|
MAGIC_WMVf, |
|
|
|
MAGIC_WMVg, |
|
|
|
MAGIC_WMVh, |
|
|
|
MAGIC_WMVi, |
|
|
|
MAGIC_WMVj |
|
|
|
}; |
|
|
|
|
|
|
|
enum HexTile_Flags { |
|
|
|
HT_RAW = 1, // tile is raw |
|
|
|
@@ -174,7 +182,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8 |
|
|
|
VmncContext * const c = (VmncContext *)avctx->priv_data; |
|
|
|
uint8_t *outptr; |
|
|
|
uint8_t *src = buf; |
|
|
|
int t, dx, dy, w, h, enc, chunks, res; |
|
|
|
int dx, dy, w, h, depth, enc, chunks, res; |
|
|
|
|
|
|
|
c->pic.reference = 1; |
|
|
|
c->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; |
|
|
|
@@ -183,81 +191,67 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8 |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
t = BE_32(src); |
|
|
|
src += 4; |
|
|
|
c->pic.key_frame = 0; |
|
|
|
c->pic.pict_type = FF_P_TYPE; |
|
|
|
|
|
|
|
chunks = t & 0xFF; |
|
|
|
if(chunks > 8) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Frame decoding is not possible. Please report sample to developers.\n"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if(chunks == 8) { |
|
|
|
int w, h, depth; |
|
|
|
c->pic.key_frame = 1; |
|
|
|
c->pic.pict_type = FF_I_TYPE; |
|
|
|
|
|
|
|
/* parse ServerInitialization struct */ |
|
|
|
src += 4; |
|
|
|
w = BE_16(src); src += 2; |
|
|
|
h = BE_16(src); src += 2; |
|
|
|
t = BE_32(src); src += 4; |
|
|
|
if(t != MAGIC_WMVi) { |
|
|
|
av_log(avctx, AV_LOG_INFO, "Invalid header: magic not found\n"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
depth = *src++; |
|
|
|
if(depth != c->bpp) { |
|
|
|
av_log(avctx, AV_LOG_INFO, "Depth mismatch. Container %i bpp, Frame data: %i bpp\n", c->bpp, depth); |
|
|
|
} |
|
|
|
src++; |
|
|
|
c->bigendian = *src++; |
|
|
|
if(c->bigendian & (~1)) { |
|
|
|
av_log(avctx, AV_LOG_INFO, "Invalid header: bigendian flag = %i\n", c->bigendian); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
//skip pixel format data |
|
|
|
src += 13; |
|
|
|
chunks = 1; // there should be one chunk with the whole frame, rest could be ignored |
|
|
|
} else { |
|
|
|
c->pic.key_frame = 0; |
|
|
|
c->pic.pict_type = FF_P_TYPE; |
|
|
|
} |
|
|
|
src += 2; |
|
|
|
chunks = BE_16(src); src += 2; |
|
|
|
while(chunks--) { |
|
|
|
// decode FramebufferUpdate struct |
|
|
|
dx = BE_16(src); src += 2; |
|
|
|
dy = BE_16(src); src += 2; |
|
|
|
w = BE_16(src); src += 2; |
|
|
|
h = BE_16(src); src += 2; |
|
|
|
if((dx + w > c->width) || (dy + h > c->height)) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Incorrect frame size: %ix%i+%ix%i of %ix%i\n", w, h, dx, dy, c->width, c->height); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
enc = BE_32(src); src += 4; |
|
|
|
if(enc != 0x00000005) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Only hextile decoding is supported for now\n"); |
|
|
|
switch(enc) { |
|
|
|
case 0: |
|
|
|
av_log(avctx, AV_LOG_INFO, "And this is raw encoding\n"); |
|
|
|
break; |
|
|
|
case 1: |
|
|
|
av_log(avctx, AV_LOG_INFO, "And this is CopyRect encoding\n"); |
|
|
|
break; |
|
|
|
case 2: |
|
|
|
av_log(avctx, AV_LOG_INFO, "And this is RRE encoding\n"); |
|
|
|
break; |
|
|
|
case 3: |
|
|
|
av_log(avctx, AV_LOG_INFO, "And this is CoRRE encoding\n"); |
|
|
|
break; |
|
|
|
default: |
|
|
|
av_log(avctx, AV_LOG_INFO, "And this is unknown encoding (%i)\n", enc); |
|
|
|
switch(enc) { |
|
|
|
case MAGIC_WMVd: // unknown |
|
|
|
src += 2; |
|
|
|
src += w * h * 8; // skip this data for now |
|
|
|
break; |
|
|
|
case MAGIC_WMVe: // unknown |
|
|
|
src += 2; |
|
|
|
break; |
|
|
|
case MAGIC_WMVf: // unknown and empty |
|
|
|
break; |
|
|
|
case MAGIC_WMVi: // ServerInitialization struct |
|
|
|
c->pic.key_frame = 1; |
|
|
|
c->pic.pict_type = FF_I_TYPE; |
|
|
|
depth = *src++; |
|
|
|
if(depth != c->bpp) { |
|
|
|
av_log(avctx, AV_LOG_INFO, "Depth mismatch. Container %i bpp, Frame data: %i bpp\n", c->bpp, depth); |
|
|
|
} |
|
|
|
src++; |
|
|
|
c->bigendian = *src++; |
|
|
|
if(c->bigendian & (~1)) { |
|
|
|
av_log(avctx, AV_LOG_INFO, "Invalid header: bigendian flag = %i\n", c->bigendian); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
//skip the rest of pixel format data |
|
|
|
src += 13; |
|
|
|
break; |
|
|
|
case 0x00000000: // raw rectangle data |
|
|
|
if((dx + w > c->width) || (dy + h > c->height)) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Incorrect frame size: %ix%i+%ix%i of %ix%i\n", w, h, dx, dy, c->width, c->height); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0]; |
|
|
|
paint_raw(outptr, w, h, src, c->bpp2, c->bigendian, c->pic.linesize[0]); |
|
|
|
src += w * h * c->bpp2; |
|
|
|
break; |
|
|
|
case 0x00000005: // HexTile encoded rectangle |
|
|
|
if((dx + w > c->width) || (dy + h > c->height)) { |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Incorrect frame size: %ix%i+%ix%i of %ix%i\n", w, h, dx, dy, c->width, c->height); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
return -1; |
|
|
|
outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0]; |
|
|
|
res = decode_hextile(c, outptr, src, w, h, c->pic.linesize[0]); |
|
|
|
if(res < 0) |
|
|
|
return -1; |
|
|
|
src += res; |
|
|
|
break; |
|
|
|
default: |
|
|
|
av_log(avctx, AV_LOG_ERROR, "Unsupported block type 0x%08X\n", enc); |
|
|
|
chunks = 0; // leave chunks decoding loop |
|
|
|
} |
|
|
|
outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0]; |
|
|
|
res = decode_hextile(c, outptr, src, w, h, c->pic.linesize[0]); |
|
|
|
if(res < 0) |
|
|
|
return -1; |
|
|
|
src += res; |
|
|
|
} |
|
|
|
*data_size = sizeof(AVFrame); |
|
|
|
*(AVFrame*)data = c->pic; |
|
|
|
|