1 /*
2 * compositor.cc --
3 *
4 * Overlay and Compositor Class object source code.
5 *
6 * Copyright (c) 1995-2002 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * A. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * B. Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * C. Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
22 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static const char rcsid[] =
36 "@(#) $Header: /usr/mash/src/repository/mash/mash-1/codec/compositor.cc,v 1.14 2002/05/21 21:18:12 chema Exp $";
37 #endif
38
39 #include <stdlib.h>
40 #ifndef WIN32
41 #include <unistd.h>
42 #endif
43 #include <string.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #ifdef WIN32
48 #include <io.h>
49 #else
50 #include <sys/file.h>
51 #endif
52 #include "module.h"
53 #include "crdef.h"
54
55 class Overlay : public TclObject {
56 public:
57 Overlay();
58 inline int width() const { return (width_); }
59 inline int height() const { return (height_); }
60 inline const u_char* image() const { return (image_); }
61 inline int transparent() const { return (transparent_); }
62 protected:
63 int command(int argc, const char*const* argv);
64 int load(const char* file, int w, int h);
65 int width_;
66 int height_;
67 u_char* image_;
68 int transparent_; /* transparent luminance */
69 };
70
71 static class OverlayClass : public TclClass {
72 public:
73 OverlayClass() : TclClass("Overlay") {}
74 TclObject* create(int /* argc */, const char*const* /* argv */) {
75 return (new Overlay());
76 }
77 } matcher_overlay;
78
79 class Compositor : public FrameModule {
80 public:
81 Compositor();
82 ~Compositor();
83 protected:
84 void reset();
85 int command(int argc, const char*const* argv);
86 void crinit(int w, int h);
87 u_char* frm_;
88 u_char* framebase_;
89 u_char* damage_;
90 struct onode {
91 Overlay* overlay;
92 int x;
93 int y;
94 int depth;
95 onode* next;
96 };
97 void attach(Overlay* o, int x, int y, int depth);
98 void move(Overlay*, int x, int y);
99 void detach(Overlay*);
100 void damage(onode*);
101 onode* overlays_;
102 };
103
104 class Compositor422 : public Compositor {
105 public:
106 virtual void recv(Buffer*);
107 void size(int w, int h);
108 void copy_block(u_char* ofrm, u_char* ochm,
109 const u_char* frm, const u_char* chm);
110 void composite(Overlay* o, int x, int y);
111 };
112
113 class Compositor420 : public Compositor {
114 public:
115 virtual void recv(Buffer*);
116 void size(int w, int h);
117 void copy_block(u_char* ofrm, u_char* ochm,
118 const u_char* frm, const u_char* chm);
119 void composite(Overlay* o, int x, int y);
120 };
121
122 static class Compositor422Class : public TclClass {
123 public:
124 Compositor422Class() : TclClass("Module/Compositor/422") {}
125 TclObject* create(int /* argc */, const char*const* /* argv */) {
126 return (new Compositor422);
127 }
128 } compositor422;
129
130 static class Compositor420Class : public TclClass {
131 public:
132 Compositor420Class() : TclClass("Module/Compositor/420") {}
133 TclObject* create(int /* argc */, const char*const* /* argv */) {
134 return (new Compositor420);
135 }
136 } compositor420;
137
138 Overlay::Overlay() : width_(0), height_(0), image_(0), transparent_(0)
139 {
140 }
141
142 int Overlay::command(int argc, const char*const* argv)
143 {
144 Tcl& tcl = Tcl::instance();
145 if (argc == 3) {
146 if (strcmp(argv[1], "transparent") == 0) {
147 transparent_ = atoi(argv[2]);
148 return (TCL_OK);
149 }
150 } else if (argc == 5) {
151 if (strcmp(argv[1], "load") == 0) {
152 const char* file = argv[2];
153 int w = atoi(argv[3]);
154 int h = atoi(argv[4]);
155 if (load(file, w, h) < 0)
156 tcl.result("-1");
157 else
158 tcl.result("");
159 return (TCL_OK);
160 }
161 }
162 return (TclObject::command(argc, argv));
163 }
164
165 int Overlay::load(const char* file, int w, int h)
166 {
167 delete[] image_;
168 image_ = 0;
169 int fd = open(file, O_RDONLY);
170 if (fd < 0)
171 return (-1);
172 width_ = w;
173 height_ = h;
174 int s = 2 * w * h;
175 image_ = new u_char[s];
176 int cc = read(fd, image_, s);
177 if (cc != s) {
178 delete[] image_;
179 image_ = 0;
180 return (-1);
181 }
182 close(fd);
183 return (0);
184 }
185
186 Compositor::Compositor()
187 : frm_(0), framebase_(0), damage_(0)
188 {
189 width_ = 0;
190 height_ = 0;
191 framesize_ = 0;
192 overlays_ = 0;
193 }
194
195 Compositor::~Compositor()
196 {
197 delete[] framebase_;
198 delete[] damage_;
199 onode* p = overlays_;
200 while (p != 0) {
201 onode* n = p->next;
202 delete p;
203 p = n;
204 }
205 }
206
207 int Compositor::command(int argc, const char*const* argv)
208 {
209 Tcl& tcl = Tcl::instance();
210 if (argc == 2) {
211 if (strcmp(argv[1], "reset") == 0) {
212 reset();
213 return (TCL_OK);
214 }
215 } else if (argc == 3) {
216 if (strcmp(argv[1], "detach") == 0) {
217 Overlay* o = (Overlay*)TclObject::lookup(argv[2]);
218 if (o == 0) {
219 tcl.result("no such overlay");
220 return (TCL_ERROR);
221 }
222 detach(o);
223 return (TCL_OK);
224 }
225 } else if (argc == 5) {
226 if (strcmp(argv[1], "move") == 0) {
227 Overlay* o = (Overlay*)TclObject::lookup(argv[2]);
228 if (o == 0) {
229 tcl.result("no such overlay");
230 return (TCL_ERROR);
231 }
232 int x = atoi(argv[3]);
233 int y = atoi(argv[4]);
234 move(o, x, y);
235 return (TCL_OK);
236 }
237 } else if (argc == 6) {
238 if (strcmp(argv[1], "attach") == 0) {
239 Overlay* o = (Overlay*)TclObject::lookup(argv[2]);
240 if (o == 0) {
241 tcl.result("no such overlay");
242 return (TCL_ERROR);
243 }
244 int x = atoi(argv[3]);
245 int y = atoi(argv[4]);
246 int depth = atoi(argv[5]);
247 attach(o, x, y, depth);
248 return (TCL_OK);
249 }
250 }
251 return (FrameModule::command(argc, argv));
252 }
253
254 void Compositor::reset()
255 {
256 while (overlays_)
257 detach(overlays_->overlay);
258 }
259
260 void Compositor::attach(Overlay* o, int x, int y, int depth)
261 {
262 x &=~ 1;
263 y &=~ 1;
264 onode* p = new onode;
265 p->overlay = o;
266 p->x = x;
267 p->y = y;
268 p->depth = depth;
269 onode** op;
270 for (op = &overlays_; *op != 0; op = &(*op)->next)
271 if (depth > (*op)->depth)
272 break;
273 p->next = *op;
274 *op = p;
275 damage(p);
276 }
277
278 void Compositor::detach(Overlay* /* o */)
279 {
280 for (onode** op = &overlays_; *op != 0; op = &(*op)->next) {
281 onode* p = (*op)->next;
282 if (*op == p) {
283 damage(p);
284 *op = p->next;
285 delete p;
286 return;
287 }
288 }
289 }
290
291 void Compositor::move(Overlay* o, int x, int y)
292 {
293 x &=~ 1;
294 y &=~ 1;
295 for (onode* p = overlays_; p != 0; p = p->next) {
296 if (p->overlay == o) {
297 damage(p);
298 p->x = x;
299 p->y = y;
300 damage(p);
301 return;
302 }
303 }
304 }
305
306 /*
307 * the overlay in onode will be added, deleted or moved.
308 * update the damage vector so we send the corresponding
309 * blocks to reflect change.
310 */
311 void Compositor::damage(onode* on)
312 {
313 int blkw = width_ >> 4;
314 int blkh = height_ >> 4;
315 int bx = on->x >> 4;
316 int bw = ((on->x + on->overlay->width() + 15) >> 4) - bx;
317 if (bx + bw > blkw)
318 bw = blkw - bx;
319 int by = on->y >> 4;
320 int bh = ((on->y + on->overlay->height() + 15) >> 4) - by;
321 if (by + bh > blkh)
322 bh = blkh - by;
323
324 u_char* p = &damage_[blkw * by + bx];
325 while (--bh >= 0) {
326 for (int k = 0; k < bw; ++k)
327 p[k] = 1;
328 p += blkw;
329 }
330 }
331
332 void Compositor::crinit(int w, int h)
333 {
334 int blkw = w >> 4;
335 int blkh = h >> 4;
336 int n = blkw * blkh;
337 delete[] damage_;
338 damage_ = new u_char[n];
339 memset(damage_, 0, n);
340 }
341
342 /*FIXME*/
343 #define VIDCAP_VPAD 1
344 void Compositor422::size(int w, int h)
345 {
346 FrameModule::size(w, h);
347 int n = 2 * framesize_ + 2 * VIDCAP_VPAD * w;
348 delete[] framebase_;
349 framebase_ = new u_char[n];
350 frm_ = framebase_ + VIDCAP_VPAD * w;
351 Compositor::crinit(w, h);
352 }
353
354 void Compositor422::copy_block(u_char* ofrm, u_char* ochm,
355 const u_char* frm, const u_char* chm)
356 {
357 int stride = width_;
358 int k;
359 for (k = 16; --k >= 0; ) {
360 *(int32_t*)&ofrm[0] = *(int32_t*)&frm[0];
361 *(int32_t*)&ofrm[4] = *(int32_t*)&frm[4];
362 *(int32_t*)&ofrm[8] = *(int32_t*)&frm[8];
363 *(int32_t*)&ofrm[12] = *(int32_t*)&frm[12];
364 ofrm += stride;
365 frm += stride;
366 }
367 stride >>= 1;
368 for (k = 16; --k >= 0; ) {
369 *(int32_t*)&ochm[0] = *(int32_t*)&chm[0];
370 *(int32_t*)&ochm[4] = *(int32_t*)&chm[4];
371 ochm += stride;
372 chm += stride;
373 }
374 ochm -= stride << 4;
375 ochm += framesize_ >> 1;
376 chm -= stride << 4;
377 chm += framesize_ >> 1;
378 for (k = 16; --k >= 0; ) {
379 *(int32_t*)&ochm[0] = *(int32_t*)&chm[0];
380 *(int32_t*)&ochm[4] = *(int32_t*)&chm[4];
381 ochm += stride;
382 chm += stride;
383 }
384 }
385
386 void Compositor422::recv(Buffer* bp)
387 {
388 const VideoFrame* vf = (VideoFrame*)bp;
389 if (!samesize(vf))
390 size(vf->width_, vf->height_);
391 YuvFrame* p = (YuvFrame*)vf;
392
393 /*
394 * 1. update our copy of the frame
395 * 2. composite all compositor items (and update crvec)
396 */
397 int blkw = width_ >> 4;
398 int blkh = height_ >> 4;
399 int blkno = 0;
400
401 int loff = 0;
402 int coff = 0;
403 int fs = framesize_;
404 u_int8_t* dam = damage_;
405 const u_int8_t* crv = p->crvec_;
406 u_int8_t* frm = p->bp_;
407 for (int y = 0; y < blkh; ++y) {
408 for (int x = 0; x < blkw; ++blkno, loff += 16, coff += 8,
409 ++x, ++crv, ++dam) {
410 /* smash damage array into a crvec */
411 int d = *dam;
412 if (d)
413 d = CR_LQ|CR_MOTION_BIT;
414 else
415 d = *crv;
416 *dam = d;
417 if (d & CR_SEND) {
418 copy_block(frm_ + loff, frm_ + fs + coff,
419 frm + loff, frm + fs + coff);
420 }
421 }
422 loff += 15 * width_;
423 coff += 15 * (width_ >> 1);
424 }
425 for (onode* o = overlays_; o != 0; o = o->next)
426 composite(o->overlay, o->x, o->y);
427 YuvFrame nf(p->ts_, frm_, damage_, p->width_, p->height_, 422);
428 target_->recv(&nf);
429 memset(damage_, 0, blkw * blkh);
430 }
431
432 void Compositor422::composite(Overlay* o, int x, int y)
433 {
434 if (x >= width_ || y >= height_)
435 return;
436
437 int off = y * width_ + x;
438 u_char* yp = frm_ + off;
439 u_char* up = frm_ + framesize_ + (off >> 1);
440 u_char* vp = up + (framesize_ >> 1);
441 int w = o->width();
442 int h = o->height();
443 if (x + w > width_)
444 w = width_ - x;
445 if (y + h > height_)
446 h = height_ - y;
447 const u_char* p = o->image();
448 if (p == 0)
449 return;
450 int trans = o->transparent();
451 while (--h >= 0) {
452 /* two pixels at a time */
453 for (int k = 0; k < w; k += 2) {
454 if (p[0] != trans) {
455 yp[k] = p[0];
456 yp[k + 1] = p[2];
457 up[k >> 1] = p[1];
458 vp[k >> 1] = p[3];
459 }
460 p += 4;
461 }
462 yp += width_;
463 up += width_ >> 1;
464 vp += width_ >> 1;
465 p += (o->width() - w) << 1;
466 }
467 }
468
469 void Compositor420::size(int w, int h)
470 {
471 FrameModule::size(w, h);
472 int fs = framesize_;
473 int n = fs + (fs >> 1) + 2 * VIDCAP_VPAD * w;
474 delete[] framebase_;
475 framebase_ = new u_char[n];
476 frm_ = framebase_ + VIDCAP_VPAD * w;
477 Compositor::crinit(w, h);
478 }
479
480 void Compositor420::copy_block(u_char* ofrm, u_char* ochm,
481 const u_char* frm, const u_char* chm)
482 {
483 int stride = width_;
484 int k;
485 for (k = 16; --k >= 0; ) {
486 *(int32_t*)&ofrm[0] = *(int32_t*)&frm[0];
487 *(int32_t*)&ofrm[4] = *(int32_t*)&frm[4];
488 *(int32_t*)&ofrm[8] = *(int32_t*)&frm[8];
489 *(int32_t*)&ofrm[12] = *(int32_t*)&frm[12];
490 ofrm += stride;
491 frm += stride;
492 }
493 stride >>= 1;
494 for (k = 8; --k >= 0; ) {
495 *(int32_t*)&ochm[0] = *(int32_t*)&chm[0];
496 *(int32_t*)&ochm[4] = *(int32_t*)&chm[4];
497 ochm += stride;
498 chm += stride;
499 }
500 ochm -= stride << 3;
501 ochm += framesize_ >> 2;
502 chm -= stride << 3;
503 chm += framesize_ >> 2;
504 for (k = 8; --k >= 0; ) {
505 *(int32_t*)&ochm[0] = *(int32_t*)&chm[0];
506 *(int32_t*)&ochm[4] = *(int32_t*)&chm[4];
507 ochm += stride;
508 chm += stride;
509 }
510 }
511
512 void Compositor420::recv(Buffer* bp)
513 {
514 const VideoFrame* vf = (VideoFrame*)bp;
515 if (!samesize(vf))
516 size(vf->width_, vf->height_);
517 YuvFrame* p = (YuvFrame*)vf;
518
519 int blkw = width_ >> 4;
520 int blkh = height_ >> 4;
521 int blkno = 0;
522
523 int loff = 0;
524 int coff = 0;
525 int fs = framesize_;
526 u_char* dam = damage_;
527 const u_int8_t* crv = p->crvec_;
528 u_int8_t* frm = p->bp_;
529 for (int y = 0; y < blkh; ++y) {
530 for (int x = 0; x < blkw; ++blkno, loff += 16, coff += 8,
531 ++x, ++crv, ++dam) {
532 /* smash damage array into a crvec */
533 int d = *dam;
534 if (d)
535 d = CR_LQ|CR_MOTION_BIT;
536 else
537 d = *crv;
538 *dam = d;
539 if (d & CR_SEND) {
540 copy_block(frm_ + loff, frm_ + fs + coff,
541 frm + loff, frm + fs + coff);
542 }
543 }
544 loff += 15 * width_;
545 coff += 7 * (width_ >> 1);
546 }
547 for (onode* o = overlays_; o != 0; o = o->next)
548 composite(o->overlay, o->x, o->y);
549
550 YuvFrame nf(p->ts_, frm_, damage_, p->width_, p->height_, 420);
551 target_->recv(&nf);
552 memset(damage_, 0, blkw * blkh);
553 }
554
555 void Compositor420::composite(Overlay* o, int x, int y)
556 {
557 if (x >= width_ || y >= height_)
558 return;
559
560 int off = y * width_;
561 u_char* yp = frm_ + off + x;
562 off = (off >> 2) + (x >> 1);
563 u_char* up = frm_ + framesize_ + off;
564 u_char* vp = up + (framesize_ >> 2);
565 int ovw = o->width();
566 int w = ovw;
567 int h = o->height();
568 if (x + w > width_)
569 w = width_ - x;
570 if (y + h > height_)
571 h = height_ - y;
572 const u_char* p = o->image();
573 if (p == 0)
574 return;
575 int trans = o->transparent();
576
577 /* convert to byte offset */
578 ovw <<= 1;
579
580 for (; h > 0; h -= 2) {
581 /* two pixels at a time, both horiz and vertically */
582 for (int k = 0; k < w; k += 2) {
583 if (p[0] != trans) {
584 yp[k] = p[0];
585 yp[k + width_] = p[ovw];
586 yp[k + 1] = p[2];
587 yp[k + 1 + width_] = p[ovw + 2];
588 up[k >> 1] = p[1];
589 vp[k >> 1] = p[3];
590 }
591 p += 4;
592 }
593 yp += width_ << 1;
594 up += width_ >> 1;
595 vp += width_ >> 1;
596 p += (ovw - w) << 1;
597 }
598 }
599
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.