root/vic/branches/cc/codec/compositor.cpp @ 4211

Revision 4211, 14.1 KB (checked in by soohyunc, 6 years ago)

sync'ing commits to the vic-mpeg4 branch
(for the commit comments, please refer to vic-mpeg4 branch's message)

(note: most of these commits done by Piers O'Hanlon)

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