From 54b55c8da0afc923129163e1d5ab0ec1fcbffd86 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Thu, 7 Sep 2006 04:01:42 +0000 Subject: [PATCH] Cursor drawing support Originally committed as revision 6183 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/vmnc.c | 172 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 167 insertions(+), 5 deletions(-) diff --git a/libavcodec/vmnc.c b/libavcodec/vmnc.c index a39bf271f0..ac50221c2e 100644 --- a/libavcodec/vmnc.c +++ b/libavcodec/vmnc.c @@ -60,6 +60,13 @@ typedef struct VmncContext { int bigendian; uint8_t pal[768]; int width, height; + + /* cursor data */ + int cur_w, cur_h; + int cur_x, cur_y; + int cur_hx, cur_hy; + uint8_t* curbits, *curmask; + uint8_t* screendta; } VmncContext; /* read pixel value from stream */ @@ -75,6 +82,93 @@ static always_inline int vmnc_get_pixel(uint8_t* buf, int bpp, int be) { } } +static void load_cursor(VmncContext *c, uint8_t *src) +{ + int i, j, p; + const int bpp = c->bpp2; + uint8_t *dst8 = c->curbits; + uint16_t *dst16 = (uint16_t*)c->curbits; + uint32_t *dst32 = (uint32_t*)c->curbits; + + for(j = 0; j < c->cur_h; j++) { + for(i = 0; i < c->cur_w; i++) { + p = vmnc_get_pixel(src, bpp, c->bigendian); + src += bpp; + if(bpp == 1) *dst8++ = p; + if(bpp == 2) *dst16++ = p; + if(bpp == 4) *dst32++ = p; + } + } + dst8 = c->curmask; + dst16 = (uint16_t*)c->curmask; + dst32 = (uint32_t*)c->curmask; + for(j = 0; j < c->cur_h; j++) { + for(i = 0; i < c->cur_w; i++) { + p = vmnc_get_pixel(src, bpp, c->bigendian); + src += bpp; + if(bpp == 1) *dst8++ = p; + if(bpp == 2) *dst16++ = p; + if(bpp == 4) *dst32++ = p; + } + } +} + +static void put_cursor(uint8_t *dst, int stride, VmncContext *c, int dx, int dy) +{ + int i, j, t; + int w, h, x, y; + w = c->cur_w; + if(c->width < c->cur_x + c->cur_w) w = c->width - c->cur_x; + h = c->cur_h; + if(c->height < c->cur_y + c->cur_h) h = c->height - c->cur_y; + x = c->cur_x; + y = c->cur_y; + if(x < 0) { + w += x; + x = 0; + } + if(y < 0) { + h += y; + y = 0; + } + + if((w < 1) || (h < 1)) return; + dst += x * c->bpp2 + y * stride; + + if(c->bpp2 == 1) { + uint8_t* cd = c->curbits, *msk = c->curmask; + for(j = 0; j < h; j++) { + for(i = 0; i < w; i++) + dst[i] = (dst[i] & cd[i]) ^ msk[i]; + msk += c->cur_w; + cd += c->cur_w; + dst += stride; + } + } else if(c->bpp2 == 2) { + uint16_t* cd = (uint16_t*)c->curbits, *msk = (uint16_t*)c->curmask; + uint16_t* dst2; + for(j = 0; j < h; j++) { + dst2 = (uint16_t*)dst; + for(i = 0; i < w; i++) + dst2[i] = (dst2[i] & cd[i]) ^ msk[i]; + msk += c->cur_w; + cd += c->cur_w; + dst += stride; + } + } else if(c->bpp2 == 4) { + uint32_t* cd = (uint32_t*)c->curbits, *msk = (uint32_t*)c->curmask; + uint32_t* dst2; + for(j = 0; j < h; j++) { + dst2 = (uint32_t*)dst; + for(i = 0; i < w; i++) + dst2[i] = (dst2[i] & cd[i]) ^ msk[i]; + msk += c->cur_w; + cd += c->cur_w; + dst += stride; + } + } +} + /* fill rectangle with given colour */ static always_inline void paint_rect(uint8_t *dst, int dx, int dy, int w, int h, int color, int bpp, int stride) { @@ -194,6 +288,31 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8 c->pic.key_frame = 0; c->pic.pict_type = FF_P_TYPE; + //restore screen after cursor + if(c->screendta) { + int i; + w = c->cur_w; + if(c->width < c->cur_x + w) w = c->width - c->cur_x; + h = c->cur_h; + if(c->height < c->cur_y + h) h = c->height - c->cur_y; + dx = c->cur_x; + if(dx < 0) { + w += dx; + dx = 0; + } + dy = c->cur_y; + if(dy < 0) { + h += dy; + dy = 0; + } + if((w > 0) && (h > 0)) { + outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0]; + for(i = 0; i < h; i++) { + memcpy(outptr, c->screendta + i * c->cur_w * c->bpp2, w * c->bpp2); + outptr += c->pic.linesize[0]; + } + } + } src += 2; chunks = BE_16(src); src += 2; while(chunks--) { @@ -202,15 +321,30 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8 w = BE_16(src); src += 2; h = BE_16(src); src += 2; enc = BE_32(src); src += 4; + outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0]; switch(enc) { - case MAGIC_WMVd: // unknown + case MAGIC_WMVd: // cursor src += 2; - src += w * h * 8; // skip this data for now + c->cur_w = w; + c->cur_h = h; + c->cur_hx = dx; + c->cur_hy = dy; + if((c->cur_hx > c->cur_w) || (c->cur_hy > c->cur_h)) { + av_log(avctx, AV_LOG_ERROR, "Cursor hot spot is not in image: %ix%i of %ix%i cursor size\n", c->cur_hx, c->cur_hy, c->cur_w, c->cur_h); + c->cur_hx = c->cur_hy = 0; + } + c->curbits = av_realloc(c->curbits, c->cur_w * c->cur_h * c->bpp2); + c->curmask = av_realloc(c->curmask, c->cur_w * c->cur_h * c->bpp2); + c->screendta = av_realloc(c->screendta, c->cur_w * c->cur_h * c->bpp2); + load_cursor(c, src); + src += w * h * c->bpp2 * 2; break; case MAGIC_WMVe: // unknown src += 2; break; - case MAGIC_WMVf: // unknown and empty + case MAGIC_WMVf: // update cursor position + c->cur_x = dx - c->cur_hx; + c->cur_y = dy - c->cur_hy; break; case MAGIC_WMVi: // ServerInitialization struct c->pic.key_frame = 1; @@ -233,7 +367,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8 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; @@ -242,7 +375,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8 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; @@ -253,6 +385,33 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8 chunks = 0; // leave chunks decoding loop } } + if(c->screendta){ + int i; + //save screen data before painting cursor + w = c->cur_w; + if(c->width < c->cur_x + w) w = c->width - c->cur_x; + h = c->cur_h; + if(c->height < c->cur_y + h) h = c->height - c->cur_y; + dx = c->cur_x; + if(dx < 0) { + w += dx; + dx = 0; + } + dy = c->cur_y; + if(dy < 0) { + h += dy; + dy = 0; + } + if((w > 0) && (h > 0)) { + outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0]; + for(i = 0; i < h; i++) { + memcpy(c->screendta + i * c->cur_w * c->bpp2, outptr, w * c->bpp2); + outptr += c->pic.linesize[0]; + } + outptr = c->pic.data[0]; + put_cursor(outptr, c->pic.linesize[0], c, c->cur_x, c->cur_y); + } + } *data_size = sizeof(AVFrame); *(AVFrame*)data = c->pic; @@ -315,6 +474,9 @@ static int decode_end(AVCodecContext *avctx) if (c->pic.data[0]) avctx->release_buffer(avctx, &c->pic); + av_free(c->curbits); + av_free(c->curmask); + av_free(c->screendta); return 0; }