Try to handle all chunks, previous scheme was not correct.

Originally committed as revision 6173 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Kostya Shishkov 2006-09-05 07:31:53 +00:00
parent c0d6fc1f73
commit 805934b3e4
1 changed files with 62 additions and 68 deletions

View File

@ -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);
}
return -1;
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;
}
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;