comparison vmnc.c @ 3684:9f77f4f577b4 libavcodec

Cursor drawing support
author kostya
date Thu, 07 Sep 2006 04:01:42 +0000
parents 2702eec8c8b9
children dd2da6e09d32
comparison
equal deleted inserted replaced
3683:dc1e28564bb2 3684:9f77f4f577b4
58 int bpp; 58 int bpp;
59 int bpp2; 59 int bpp2;
60 int bigendian; 60 int bigendian;
61 uint8_t pal[768]; 61 uint8_t pal[768];
62 int width, height; 62 int width, height;
63
64 /* cursor data */
65 int cur_w, cur_h;
66 int cur_x, cur_y;
67 int cur_hx, cur_hy;
68 uint8_t* curbits, *curmask;
69 uint8_t* screendta;
63 } VmncContext; 70 } VmncContext;
64 71
65 /* read pixel value from stream */ 72 /* read pixel value from stream */
66 static always_inline int vmnc_get_pixel(uint8_t* buf, int bpp, int be) { 73 static always_inline int vmnc_get_pixel(uint8_t* buf, int bpp, int be) {
67 switch(bpp * 2 + be) { 74 switch(bpp * 2 + be) {
70 case 4: return LE_16(buf); 77 case 4: return LE_16(buf);
71 case 5: return BE_16(buf); 78 case 5: return BE_16(buf);
72 case 8: return LE_32(buf); 79 case 8: return LE_32(buf);
73 case 9: return BE_32(buf); 80 case 9: return BE_32(buf);
74 default: return 0; 81 default: return 0;
82 }
83 }
84
85 static void load_cursor(VmncContext *c, uint8_t *src)
86 {
87 int i, j, p;
88 const int bpp = c->bpp2;
89 uint8_t *dst8 = c->curbits;
90 uint16_t *dst16 = (uint16_t*)c->curbits;
91 uint32_t *dst32 = (uint32_t*)c->curbits;
92
93 for(j = 0; j < c->cur_h; j++) {
94 for(i = 0; i < c->cur_w; i++) {
95 p = vmnc_get_pixel(src, bpp, c->bigendian);
96 src += bpp;
97 if(bpp == 1) *dst8++ = p;
98 if(bpp == 2) *dst16++ = p;
99 if(bpp == 4) *dst32++ = p;
100 }
101 }
102 dst8 = c->curmask;
103 dst16 = (uint16_t*)c->curmask;
104 dst32 = (uint32_t*)c->curmask;
105 for(j = 0; j < c->cur_h; j++) {
106 for(i = 0; i < c->cur_w; i++) {
107 p = vmnc_get_pixel(src, bpp, c->bigendian);
108 src += bpp;
109 if(bpp == 1) *dst8++ = p;
110 if(bpp == 2) *dst16++ = p;
111 if(bpp == 4) *dst32++ = p;
112 }
113 }
114 }
115
116 static void put_cursor(uint8_t *dst, int stride, VmncContext *c, int dx, int dy)
117 {
118 int i, j, t;
119 int w, h, x, y;
120 w = c->cur_w;
121 if(c->width < c->cur_x + c->cur_w) w = c->width - c->cur_x;
122 h = c->cur_h;
123 if(c->height < c->cur_y + c->cur_h) h = c->height - c->cur_y;
124 x = c->cur_x;
125 y = c->cur_y;
126 if(x < 0) {
127 w += x;
128 x = 0;
129 }
130 if(y < 0) {
131 h += y;
132 y = 0;
133 }
134
135 if((w < 1) || (h < 1)) return;
136 dst += x * c->bpp2 + y * stride;
137
138 if(c->bpp2 == 1) {
139 uint8_t* cd = c->curbits, *msk = c->curmask;
140 for(j = 0; j < h; j++) {
141 for(i = 0; i < w; i++)
142 dst[i] = (dst[i] & cd[i]) ^ msk[i];
143 msk += c->cur_w;
144 cd += c->cur_w;
145 dst += stride;
146 }
147 } else if(c->bpp2 == 2) {
148 uint16_t* cd = (uint16_t*)c->curbits, *msk = (uint16_t*)c->curmask;
149 uint16_t* dst2;
150 for(j = 0; j < h; j++) {
151 dst2 = (uint16_t*)dst;
152 for(i = 0; i < w; i++)
153 dst2[i] = (dst2[i] & cd[i]) ^ msk[i];
154 msk += c->cur_w;
155 cd += c->cur_w;
156 dst += stride;
157 }
158 } else if(c->bpp2 == 4) {
159 uint32_t* cd = (uint32_t*)c->curbits, *msk = (uint32_t*)c->curmask;
160 uint32_t* dst2;
161 for(j = 0; j < h; j++) {
162 dst2 = (uint32_t*)dst;
163 for(i = 0; i < w; i++)
164 dst2[i] = (dst2[i] & cd[i]) ^ msk[i];
165 msk += c->cur_w;
166 cd += c->cur_w;
167 dst += stride;
168 }
75 } 169 }
76 } 170 }
77 171
78 /* fill rectangle with given colour */ 172 /* fill rectangle with given colour */
79 static always_inline void paint_rect(uint8_t *dst, int dx, int dy, int w, int h, int color, int bpp, int stride) 173 static always_inline void paint_rect(uint8_t *dst, int dx, int dy, int w, int h, int color, int bpp, int stride)
192 } 286 }
193 287
194 c->pic.key_frame = 0; 288 c->pic.key_frame = 0;
195 c->pic.pict_type = FF_P_TYPE; 289 c->pic.pict_type = FF_P_TYPE;
196 290
291 //restore screen after cursor
292 if(c->screendta) {
293 int i;
294 w = c->cur_w;
295 if(c->width < c->cur_x + w) w = c->width - c->cur_x;
296 h = c->cur_h;
297 if(c->height < c->cur_y + h) h = c->height - c->cur_y;
298 dx = c->cur_x;
299 if(dx < 0) {
300 w += dx;
301 dx = 0;
302 }
303 dy = c->cur_y;
304 if(dy < 0) {
305 h += dy;
306 dy = 0;
307 }
308 if((w > 0) && (h > 0)) {
309 outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
310 for(i = 0; i < h; i++) {
311 memcpy(outptr, c->screendta + i * c->cur_w * c->bpp2, w * c->bpp2);
312 outptr += c->pic.linesize[0];
313 }
314 }
315 }
197 src += 2; 316 src += 2;
198 chunks = BE_16(src); src += 2; 317 chunks = BE_16(src); src += 2;
199 while(chunks--) { 318 while(chunks--) {
200 dx = BE_16(src); src += 2; 319 dx = BE_16(src); src += 2;
201 dy = BE_16(src); src += 2; 320 dy = BE_16(src); src += 2;
202 w = BE_16(src); src += 2; 321 w = BE_16(src); src += 2;
203 h = BE_16(src); src += 2; 322 h = BE_16(src); src += 2;
204 enc = BE_32(src); src += 4; 323 enc = BE_32(src); src += 4;
324 outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
205 switch(enc) { 325 switch(enc) {
206 case MAGIC_WMVd: // unknown 326 case MAGIC_WMVd: // cursor
207 src += 2; 327 src += 2;
208 src += w * h * 8; // skip this data for now 328 c->cur_w = w;
329 c->cur_h = h;
330 c->cur_hx = dx;
331 c->cur_hy = dy;
332 if((c->cur_hx > c->cur_w) || (c->cur_hy > c->cur_h)) {
333 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);
334 c->cur_hx = c->cur_hy = 0;
335 }
336 c->curbits = av_realloc(c->curbits, c->cur_w * c->cur_h * c->bpp2);
337 c->curmask = av_realloc(c->curmask, c->cur_w * c->cur_h * c->bpp2);
338 c->screendta = av_realloc(c->screendta, c->cur_w * c->cur_h * c->bpp2);
339 load_cursor(c, src);
340 src += w * h * c->bpp2 * 2;
209 break; 341 break;
210 case MAGIC_WMVe: // unknown 342 case MAGIC_WMVe: // unknown
211 src += 2; 343 src += 2;
212 break; 344 break;
213 case MAGIC_WMVf: // unknown and empty 345 case MAGIC_WMVf: // update cursor position
346 c->cur_x = dx - c->cur_hx;
347 c->cur_y = dy - c->cur_hy;
214 break; 348 break;
215 case MAGIC_WMVi: // ServerInitialization struct 349 case MAGIC_WMVi: // ServerInitialization struct
216 c->pic.key_frame = 1; 350 c->pic.key_frame = 1;
217 c->pic.pict_type = FF_I_TYPE; 351 c->pic.pict_type = FF_I_TYPE;
218 depth = *src++; 352 depth = *src++;
231 case 0x00000000: // raw rectangle data 365 case 0x00000000: // raw rectangle data
232 if((dx + w > c->width) || (dy + h > c->height)) { 366 if((dx + w > c->width) || (dy + h > c->height)) {
233 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); 367 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);
234 return -1; 368 return -1;
235 } 369 }
236 outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
237 paint_raw(outptr, w, h, src, c->bpp2, c->bigendian, c->pic.linesize[0]); 370 paint_raw(outptr, w, h, src, c->bpp2, c->bigendian, c->pic.linesize[0]);
238 src += w * h * c->bpp2; 371 src += w * h * c->bpp2;
239 break; 372 break;
240 case 0x00000005: // HexTile encoded rectangle 373 case 0x00000005: // HexTile encoded rectangle
241 if((dx + w > c->width) || (dy + h > c->height)) { 374 if((dx + w > c->width) || (dy + h > c->height)) {
242 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); 375 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);
243 return -1; 376 return -1;
244 } 377 }
245 outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
246 res = decode_hextile(c, outptr, src, w, h, c->pic.linesize[0]); 378 res = decode_hextile(c, outptr, src, w, h, c->pic.linesize[0]);
247 if(res < 0) 379 if(res < 0)
248 return -1; 380 return -1;
249 src += res; 381 src += res;
250 break; 382 break;
251 default: 383 default:
252 av_log(avctx, AV_LOG_ERROR, "Unsupported block type 0x%08X\n", enc); 384 av_log(avctx, AV_LOG_ERROR, "Unsupported block type 0x%08X\n", enc);
253 chunks = 0; // leave chunks decoding loop 385 chunks = 0; // leave chunks decoding loop
386 }
387 }
388 if(c->screendta){
389 int i;
390 //save screen data before painting cursor
391 w = c->cur_w;
392 if(c->width < c->cur_x + w) w = c->width - c->cur_x;
393 h = c->cur_h;
394 if(c->height < c->cur_y + h) h = c->height - c->cur_y;
395 dx = c->cur_x;
396 if(dx < 0) {
397 w += dx;
398 dx = 0;
399 }
400 dy = c->cur_y;
401 if(dy < 0) {
402 h += dy;
403 dy = 0;
404 }
405 if((w > 0) && (h > 0)) {
406 outptr = c->pic.data[0] + dx * c->bpp2 + dy * c->pic.linesize[0];
407 for(i = 0; i < h; i++) {
408 memcpy(c->screendta + i * c->cur_w * c->bpp2, outptr, w * c->bpp2);
409 outptr += c->pic.linesize[0];
410 }
411 outptr = c->pic.data[0];
412 put_cursor(outptr, c->pic.linesize[0], c, c->cur_x, c->cur_y);
254 } 413 }
255 } 414 }
256 *data_size = sizeof(AVFrame); 415 *data_size = sizeof(AVFrame);
257 *(AVFrame*)data = c->pic; 416 *(AVFrame*)data = c->pic;
258 417
313 VmncContext * const c = (VmncContext *)avctx->priv_data; 472 VmncContext * const c = (VmncContext *)avctx->priv_data;
314 473
315 if (c->pic.data[0]) 474 if (c->pic.data[0])
316 avctx->release_buffer(avctx, &c->pic); 475 avctx->release_buffer(avctx, &c->pic);
317 476
477 av_free(c->curbits);
478 av_free(c->curmask);
479 av_free(c->screendta);
318 return 0; 480 return 0;
319 } 481 }
320 482
321 AVCodec vmnc_decoder = { 483 AVCodec vmnc_decoder = {
322 "VMware video", 484 "VMware video",