/* * Copyright (c) 1995 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Network Research * Group at Lawrence Berkeley National Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char rcsid[] = "@(#) $Header: /cs/research/mice/starship/src/local/CVS_repository/vic/codec/compositor.cpp,v 1.1 1999/09/09 12:45:39 piers Exp $ (LBL)"; #endif #include #ifndef WIN32 #include #endif #include #include #include #include #ifdef WIN32 #include #else #include #endif #include "module.h" #include "crdef.h" class Overlay : public TclObject { public: Overlay(); inline int width() const { return (width_); } inline int height() const { return (height_); } inline const u_char* image() const { return (image_); } inline int transparent() const { return (transparent_); } protected: int command(int argc, const char*const* argv); int load(const char* file, int w, int h); int width_; int height_; u_char* image_; int transparent_; /* transparent luminance */ }; static class OverlayMatcher : public Matcher { public: OverlayMatcher() : Matcher("overlay") {} TclObject* match(const char*) { return (new Overlay()); } } matcher_overlay; class Compositor : public Module { public: Compositor(int ft); ~Compositor(); protected: void reset(); int command(int argc, const char*const* argv); void crinit(int w, int h); u_char* frm_; u_char* framebase_; u_char* damage_; struct onode { Overlay* overlay; int x; int y; int depth; onode* next; }; void attach(Overlay* o, int x, int y, int depth); void move(Overlay*, int x, int y); void detach(Overlay*); void damage(onode*); onode* overlays_; }; class Compositor422 : public Compositor { public: Compositor422(); virtual int consume(const VideoFrame*); void size(int w, int h); void copy_block(u_char* ofrm, u_char* ochm, const u_char* frm, const u_char* chm); void composite(Overlay* o, int x, int y); }; class Compositor411 : public Compositor { public: Compositor411(); virtual int consume(const VideoFrame*); void size(int w, int h); void copy_block(u_char* ofrm, u_char* ochm, const u_char* frm, const u_char* chm); void composite(Overlay* o, int x, int y); }; static class CompositorMatcher : public Matcher { public: CompositorMatcher() : Matcher("module") {} TclObject* match(const char* fmt) { if (strcasecmp(fmt, "compositor/422") == 0) return (new Compositor422); if (strcasecmp(fmt, "compositor/411") == 0) return (new Compositor411); return (0); } } compositor; Overlay::Overlay() : image_(0), width_(0), height_(0), transparent_(0) { } int Overlay::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "transparent") == 0) { transparent_ = atoi(argv[2]); return (TCL_OK); } } else if (argc == 5) { if (strcmp(argv[1], "load") == 0) { const char* file = argv[2]; int w = atoi(argv[3]); int h = atoi(argv[4]); if (load(file, w, h) < 0) tcl.result("-1"); else tcl.result("0"); return (TCL_OK); } } return (TclObject::command(argc, argv)); } int Overlay::load(const char* file, int w, int h) { delete image_; image_ = 0; int fd = open(file, O_RDONLY); if (fd < 0) return (-1); width_ = w; height_ = h; int s = 2 * w * h; image_ = new u_char[s]; int cc = read(fd, image_, s); if (cc != s) { delete image_; image_ = 0; return (-1); } close(fd); return (0); } Compositor::Compositor(int ft) : Module(ft), frm_(0), framebase_(0), damage_(0) { width_ = 0; height_ = 0; framesize_ = 0; overlays_ = 0; } Compositor::~Compositor() { delete framebase_; delete damage_; onode* p = overlays_; while (p != 0) { onode* n = p->next; delete p; p = n; } } int Compositor::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "reset") == 0) { reset(); return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "detach") == 0) { Overlay* o = (Overlay*)TclObject::lookup(argv[2]); if (o == 0) { tcl.result("no such overlay"); return (TCL_ERROR); } detach(o); return (TCL_OK); } } else if (argc == 5) { if (strcmp(argv[1], "move") == 0) { Overlay* o = (Overlay*)TclObject::lookup(argv[2]); if (o == 0) { tcl.result("no such overlay"); return (TCL_ERROR); } int x = atoi(argv[3]); int y = atoi(argv[4]); move(o, x, y); return (TCL_OK); } } else if (argc == 6) { if (strcmp(argv[1], "attach") == 0) { Overlay* o = (Overlay*)TclObject::lookup(argv[2]); if (o == 0) { tcl.result("no such overlay"); return (TCL_ERROR); } int x = atoi(argv[3]); int y = atoi(argv[4]); int depth = atoi(argv[5]); attach(o, x, y, depth); return (TCL_OK); } } return (Module::command(argc, argv)); } void Compositor::reset() { while (overlays_) detach(overlays_->overlay); } void Compositor::attach(Overlay* o, int x, int y, int depth) { x &=~ 1; y &=~ 1; onode* p = new onode; p->overlay = o; p->x = x; p->y = y; p->depth; onode** op; for (op = &overlays_; *op != 0; op = &(*op)->next) if (depth > (*op)->depth) break; p->next = *op; *op = p; damage(p); } void Compositor::detach(Overlay* o) { for (onode** op = &overlays_; *op != 0; op = &(*op)->next) { onode* p = (*op)->next; if (*op == p) { damage(p); *op = p->next; delete p; return; } } } void Compositor::move(Overlay* o, int x, int y) { x &=~ 1; y &=~ 1; for (onode* p = overlays_; p != 0; p = p->next) { if (p->overlay == o) { damage(p); p->x = x; p->y = y; damage(p); return; } } } /* * the overlay in onode will be added, deleted or moved. * update the damage vector so we send the corresponding * blocks to reflect change. */ void Compositor::damage(onode* on) { int blkw = width_ >> 4; int blkh = height_ >> 4; int bx = on->x >> 4; int bw = ((on->x + on->overlay->width() + 15) >> 4) - bx; if (bx + bw > blkw) bw = blkw - bx; int by = on->y >> 4; int bh = ((on->y + on->overlay->height() + 15) >> 4) - by; if (by + bh > blkh) bh = blkh - by; u_char* p = &damage_[blkw * by + bx]; while (--bh >= 0) { for (int k = 0; k < bw; ++k) p[k] = 1; p += blkw; } } void Compositor::crinit(int w, int h) { int blkw = w >> 4; int blkh = h >> 4; int n = blkw * blkh; delete damage_; damage_ = new u_char[n]; memset(damage_, 0, n); } Compositor422::Compositor422() : Compositor(FT_YUV_422) { } /*XXX*/ #define GRABBER_VPAD 1 void Compositor422::size(int w, int h) { Module::size(w, h); int n = 2 * framesize_ + 2 * GRABBER_VPAD * w; delete framebase_; framebase_ = new u_char[n]; frm_ = framebase_ + GRABBER_VPAD * w; Compositor::crinit(w, h); } void Compositor422::copy_block(u_char* ofrm, u_char* ochm, const u_char* frm, const u_char* chm) { int stride = width_; int k; for (k = 16; --k >= 0; ) { *(int32_t*)&ofrm[0] = *(int32_t*)&frm[0]; *(int32_t*)&ofrm[4] = *(int32_t*)&frm[4]; *(int32_t*)&ofrm[8] = *(int32_t*)&frm[8]; *(int32_t*)&ofrm[12] = *(int32_t*)&frm[12]; ofrm += stride; frm += stride; } stride >>= 1; for (k = 16; --k >= 0; ) { *(int32_t*)&ochm[0] = *(int32_t*)&chm[0]; *(int32_t*)&ochm[4] = *(int32_t*)&chm[4]; ochm += stride; chm += stride; } ochm -= stride << 4; ochm += framesize_ >> 1; chm -= stride << 4; chm += framesize_ >> 1; for (k = 16; --k >= 0; ) { *(int32_t*)&ochm[0] = *(int32_t*)&chm[0]; *(int32_t*)&ochm[4] = *(int32_t*)&chm[4]; ochm += stride; chm += stride; } } int Compositor422::consume(const VideoFrame* vf) { if (!samesize(vf)) size(vf->width_, vf->height_); YuvFrame* p = (YuvFrame*)vf; /* * 1. update our copy of the frame * 2. composite all compositor items (and update crvec) */ int blkw = width_ >> 4; int blkh = height_ >> 4; int blkno = 0; int loff = 0; int coff = 0; int fs = framesize_; u_int8_t* dam = damage_; const u_int8_t* crv = p->crvec_; u_int8_t* frm = p->bp_; for (int y = 0; y < blkh; ++y) { for (int x = 0; x < blkw; ++blkno, loff += 16, coff += 8, ++x, ++crv, ++dam) { /* smash damage array into a crvec */ int d = *dam; if (d) d = CR_SEND|CR_MOTION; else d = *crv; *dam = d; if (d & CR_SEND) { copy_block(frm_ + loff, frm_ + fs + coff, frm + loff, frm + fs + coff); } } loff += 15 * width_; coff += 15 * (width_ >> 1); } for (onode* o = overlays_; o != 0; o = o->next) composite(o->overlay, o->x, o->y); YuvFrame nf(p->ts_, frm_, damage_, p->width_, p->height_); int cc = target_->consume(&nf); memset(damage_, 0, blkw * blkh); return (cc); } void Compositor422::composite(Overlay* o, int x, int y) { if (x >= width_ || y >= height_) return; int off = y * width_ + x; u_char* yp = frm_ + off; u_char* up = frm_ + framesize_ + (off >> 1); u_char* vp = up + (framesize_ >> 1); int w = o->width(); int h = o->height(); if (x + w > width_) w = width_ - x; if (y + h > height_) h = height_ - y; const u_char* p = o->image(); if (p == 0) return; int trans = o->transparent(); while (--h >= 0) { /* two pixels at a time */ for (int k = 0; k < w; k += 2) { if (p[0] != trans) { yp[k] = p[0]; yp[k + 1] = p[2]; up[k >> 1] = p[1]; vp[k >> 1] = p[3]; } p += 4; } yp += width_; up += width_ >> 1; vp += width_ >> 1; p += (o->width() - w) << 1; } } Compositor411::Compositor411() : Compositor(FT_YUV_411) { } void Compositor411::size(int w, int h) { Module::size(w, h); int fs = framesize_; int n = fs + (fs >> 1) + 2 * GRABBER_VPAD * w; delete framebase_; framebase_ = new u_char[n]; frm_ = framebase_ + GRABBER_VPAD * w; Compositor::crinit(w, h); } void Compositor411::copy_block(u_char* ofrm, u_char* ochm, const u_char* frm, const u_char* chm) { int stride = width_; int k; for (k = 16; --k >= 0; ) { *(int32_t*)&ofrm[0] = *(int32_t*)&frm[0]; *(int32_t*)&ofrm[4] = *(int32_t*)&frm[4]; *(int32_t*)&ofrm[8] = *(int32_t*)&frm[8]; *(int32_t*)&ofrm[12] = *(int32_t*)&frm[12]; ofrm += stride; frm += stride; } stride >>= 1; for (k = 8; --k >= 0; ) { *(int32_t*)&ochm[0] = *(int32_t*)&chm[0]; *(int32_t*)&ochm[4] = *(int32_t*)&chm[4]; ochm += stride; chm += stride; } ochm -= stride << 3; ochm += framesize_ >> 2; chm -= stride << 3; chm += framesize_ >> 2; for (k = 8; --k >= 0; ) { *(int32_t*)&ochm[0] = *(int32_t*)&chm[0]; *(int32_t*)&ochm[4] = *(int32_t*)&chm[4]; ochm += stride; chm += stride; } } int Compositor411::consume(const VideoFrame* vf) { if (!samesize(vf)) size(vf->width_, vf->height_); YuvFrame* p = (YuvFrame*)vf; int blkw = width_ >> 4; int blkh = height_ >> 4; int blkno = 0; int loff = 0; int coff = 0; int fs = framesize_; u_char* dam = damage_; const u_int8_t* crv = p->crvec_; u_int8_t* frm = p->bp_; for (int y = 0; y < blkh; ++y) { for (int x = 0; x < blkw; ++blkno, loff += 16, coff += 8, ++x, ++crv, ++dam) { /* smash damage array into a crvec */ int d = *dam; if (d) d = CR_SEND|CR_MOTION; else d = *crv; *dam = d; if (d & CR_SEND) { copy_block(frm_ + loff, frm_ + fs + coff, frm + loff, frm + fs + coff); } } loff += 15 * width_; coff += 7 * (width_ >> 1); } for (onode* o = overlays_; o != 0; o = o->next) composite(o->overlay, o->x, o->y); YuvFrame nf(p->ts_, frm_, damage_, p->width_, p->height_); int cc = target_->consume(&nf); memset(damage_, 0, blkw * blkh); return (cc); } void Compositor411::composite(Overlay* o, int x, int y) { if (x >= width_ || y >= height_) return; int off = y * width_; u_char* yp = frm_ + off + x; off = (off >> 2) + (x >> 1); u_char* up = frm_ + framesize_ + off; u_char* vp = up + (framesize_ >> 2); int ovw = o->width(); int w = ovw; int h = o->height(); if (x + w > width_) w = width_ - x; if (y + h > height_) h = height_ - y; const u_char* p = o->image(); if (p == 0) return; int trans = o->transparent(); /* convert to byte offset */ ovw <<= 1; for (; h > 0; h -= 2) { /* two pixels at a time, both horiz and vertically */ for (int k = 0; k < w; k += 2) { if (p[0] != trans) { yp[k] = p[0]; yp[k + width_] = p[ovw]; yp[k + 1] = p[2]; yp[k + 1 + width_] = p[ovw + 2]; up[k >> 1] = p[1]; vp[k >> 1] = p[3]; } p += 4; } yp += width_ << 1; up += width_ >> 1; vp += width_ >> 1; p += (ovw - w) << 1; } }