Logo Search packages:      
Sourcecode: vic version File versions

grabber-plx.cpp

/*
 * Copyright 1995 Apple Computer, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * APPLE COMPUTER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Apple Computer shall not be
 * used in advertising or otherwise to promote the sale, use or other dealings
 * in this Software without prior written authorization from Apple Computer.
 */
/*
 * 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/video/grabber-plx.cpp,v 1.1 1999/09/09 12:52:53 piers Exp $ (LBL)";
#endif

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>

#ifdef USE_SHM
#include <sys/ipc.h>
#include <sys/shm.h>
#if !defined(__svr4__) && !defined(__hpux)
extern "C" {
#include <sys/shm.h>
int shmget(key_t, int, int);
char *shmat(int, char*, int);
int shmdt(char*);
int shmctl(int, int, struct shm_ds *);
}
#endif
#endif

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef USE_SHM
extern "C" {
#include <X11/extensions/XShm.h>
}
#endif

/*XXX*/
#ifdef __svr4__
extern "C" {
#include <XPlxExt.h>
}
#else
#include "plxfuncs.h"
#endif

#include "grabber.h"
#include "module.h"
#include "vw.h"
#include "vic_tcl.h"
#include "device-input.h"
#include "transmitter.h"
#include "rgb-converter.h"

#define NTSC_WIDTH 640
#define NTSC_HEIGHT 480
#define PAL_WIDTH 768
#define PAL_HEIGHT 576

class PlxWindow : public BareWindow {
public:
      PlxWindow(const char* name, XVisualInfo*, int port);
      virtual ~PlxWindow();
      void capture(u_int8_t* frm);
      void setsize(int w, int h);

      void port(const char *s);
      inline void hue(int v) { hue_ = v; setctrl(); }
      inline void saturation(int v) { saturation_ = v; setctrl(); }
      inline void brightness(int v) { brightness_ = v; setctrl(); }
      inline void contrast(int v) { contrast_ = v; setctrl(); }

      void freeze_frame(sigset_t* ss);
      void release_frame(sigset_t* ss);
      virtual void redraw() { need_refresh_ = 1; }

      inline int basewidth() { return (format_width_); }
      inline int baseheight() { return (format_height_); }

      void setq(int q);
      inline GC gc() const { return (gc_); }
protected:
      GC gc_;
      int need_refresh_;
      u_int format_width_, format_height_, format_offset_;
      int hue_, saturation_, brightness_, contrast_;
      int port_;
      int format_;
      void setctrl();
};

class PlxGrabber : public Grabber {
protected:
      PlxGrabber();
      virtual ~PlxGrabber();
public:
      virtual int command(int argc, const char *const *argv);
      void init();
protected:
      int lookup_visual();
      virtual void setsize() = 0;
      int decimate_;
      PlxWindow* capwin_;
      XVisualInfo vinfo_;
};

class Plx422Grabber : public PlxGrabber {
public:
      Plx422Grabber();
      ~Plx422Grabber();
      virtual int grab();
      virtual void setsize();
protected:
      void capture();
      StandardVideoImage* image_;
      RGB_Converter* converter_;
};

class Plx411Grabber : public Plx422Grabber {
public:
      virtual void setsize();
};

class PlxCIFGrabber : public Plx422Grabber {
public:
      virtual void setsize();
};

class PlxJpegGrabber : public PlxGrabber {
public:
      PlxJpegGrabber();
      ~PlxJpegGrabber();
      virtual int grab();
      virtual void setsize();
      virtual int command(int argc, const char *const *argv);
protected:
      int capture(u_int8_t* bp);
      int q_;
      XPlxCImage *cimage_;
};

static class PlxDevice : public InputDevice {
 public:
      PlxDevice(const char*);
      virtual int command(int argc, const char*const* argv);
} plx_device("parallax");

PlxDevice::PlxDevice(const char *s) : InputDevice(s) 
{
      attributes_ = "\
format { 422 411 jpeg } \
size { small large cif } \
port { Input-1 Input-2 }";
}

int PlxDevice::command(int argc, const char*const* argv)
{
      Tcl& tcl = Tcl::instance();
      if (argc == 3 && strcmp(argv[1], "open") == 0) {
            const char* fmt = argv[2];
            TclObject* o = 0;
            if (strcmp(fmt, "jpeg") == 0)
                  o = new PlxJpegGrabber;
            else if (strcmp(fmt, "422") == 0)
                  o = new Plx422Grabber;
            else if (strcmp(fmt, "411") == 0)
                  o = new Plx411Grabber;
            else if (strcmp(fmt, "cif") == 0)
                  o = new PlxCIFGrabber;
            if (o != 0)
                  Tcl::instance().result(o->name());
            return (TCL_OK);
      }
      return (InputDevice::command(argc, argv));
}

PlxWindow::PlxWindow(const char* name, XVisualInfo* vinfo, int port)
      : BareWindow(name, vinfo)
{
      gc_ = Tk_GetGC(tk_, 0, 0);
      
      /*
       * query the server to get hardware/signal information.
       */
      Tk_MakeWindowExist(tk_);
      Window window = Tk_WindowId(tk_);
      plx_IO* plxio = XPlxQueryConfig(dpy_, window, gc_);
      if (plxio->hardware != PLX_XVIDEO_24)
            /* shouldn't happen. */
            abort();

      /* go through the list of signals and find an active signal */

      plx_IO_list *il;
      /* find a pointer to channel one input */
      for (il = plxio->inputs; il->channel != port; il = il->next_IO)
            ;

      plx_signal* sig = 0;
      plx_signal_list *sl;
      for (sl = il->signal_list; sl != 0; sl = sl->next_signal) {
            /*
             * do an input select
             * we are only using input 0 so it, and PLX_COMP are hard coded
             * we also know that all the XVideo hardware can do is PLX_RGB24
             */
            format_ = sl->signal->standard;
            XPlxVideoInputSelect(dpy_, window, gc_, port,
                             format_, PLX_COMP, PLX_RGB24);

            /* now do a query video to find out if there is sync */
            sig = XPlxQueryVideo(dpy_, window, gc_);
            if (sig->sync_ok)
                  break;
      }
      if (sig == 0) {
            /*XXX don't exit!*/
            fprintf(stderr, "no video connected to input 0\n");
            exit(1);
      }
      port_ = port;
      /* maintain 4:3 aspect ratio */
      format_width_ = sig->w;
      format_height_ = (format_width_ * 3) / 4;
      format_offset_ = sig->h - format_height_ + 1;

      XPlxVideoTag(dpy_, window, gc_, PLX_VIDEO);
      XPlxVideoValueQuery(dpy_, window, gc_,
                      &saturation_, &contrast_, &hue_, &brightness_);
}

PlxWindow::~PlxWindow()
{
      Tk_FreeGC(dpy_, gc_);
}

void PlxWindow::setsize(int w, int h)
{
      BareWindow::setsize(w, h);
      /* Start the video display */
      Tcl::instance().evalc("update idletasks");/*XXX*/
      XPlxVideoSqueezeLive(dpy_, Tk_WindowId(tk_), gc_,
                       0, format_offset_, format_width_, format_height_,
                       0, 0, width_, height_);
}

void PlxWindow::setctrl()
{
      if (tk_ != 0)
            XPlxVideoValueLoad(dpy_, Tk_WindowId(tk_), gc_,
                           saturation_, contrast_, hue_, brightness_);
}

void PlxWindow::port(const char* s)
{
      port_ = (strcasecmp(s, "input-1") == 0) ? PLX_INPUT_0 : PLX_INPUT_1;
      /*
       * XXX This won't work if we have different signal types
       * on the different ports.
       */
      XPlxVideoInputSelect(dpy_, Tk_WindowId(tk_), gc_,
                       port_, format_, PLX_COMP, PLX_RGB24);
}

void PlxWindow::freeze_frame(sigset_t* ss)
{
      sigset_t fullset;
      sigfillset(&fullset);
      sigprocmask(SIG_SETMASK, &fullset, ss);
#if GRAB_SERVER
      XGrabServer(dpy_);
#endif
#ifdef notdef
      /*XXX need toplevel window */
      XRaiseWindow(dpy_, Tk_WindowId(tk_));
#endif
      if (need_refresh_) {
            XPlxVideoTag(dpy_, Tk_WindowId(tk_), gc_, PLX_VIDEO);
            XPlxVideoSqueezeLive(dpy_, Tk_WindowId(tk_), gc_,
                             0, format_offset_,
                             format_width_, format_height_,
                             0, 0, width_, height_);
      }
#ifdef notdef
      XSync(dpy_, 0);
      XPlxVideoSqueezeStill(dpy_, Tk_WindowId(tk_), gc_,
            0, format_offset_, format_width_, format_height_,
            0, 0, width_, height_);
#endif
}

void PlxWindow::release_frame(sigset_t* ss)
{
      XUngrabServer(dpy_);
      sync();
      (void)sigprocmask(SIG_SETMASK, ss, 0);
      if (need_refresh_) {
            XPlxVideoTag(dpy_, Tk_WindowId(tk_), gc_, PLX_VIDEO_OVR);
            need_refresh_ = 0;
      }
}

extern int quality_to_qfactor(int);

void PlxWindow::setq(int q)
{
      char *table;
      int size = MakeQTables(quality_to_qfactor(q), (unsigned char**)&table);
      XPlxPutTable(dpy_, Tk_WindowId(tk_), gc_,
#ifdef __hpux
                 (short *)
#endif
                 table, size, 0 /* compress */);
      free(table);
}

PlxGrabber::PlxGrabber() : capwin_(0), decimate_(0)
{
      if (lookup_visual() < 0)
            status_ = -1;
}

PlxGrabber::~PlxGrabber()
{
}

int PlxGrabber::lookup_visual()
{
      Tk_Window tk = Tcl::instance().tkmain();
      Display* dpy = Tk_Display(tk);
      int majop, eventbase, errbase;
      if (XQueryExtension(dpy, "ParallaxVideo", &majop,
                      &eventbase, &errbase) &&
          (XMatchVisualInfo(Tk_Display(tk), Tk_ScreenNumber(tk),
                        24, TrueColor, &vinfo_) ||
           XMatchVisualInfo(Tk_Display(tk), Tk_ScreenNumber(tk),
                        32, TrueColor, &vinfo_))) {
            return (0);
      }
      return (-1);
}

int PlxGrabber::command(int argc, const char * const*argv)
{
      Tcl &tcl = Tcl::instance();
      if (argc == 2) {
            if (strcmp(argv[1], "need-capwin") == 0) {
                  tcl.result("1");
                  return (TCL_OK);
            }
      } else if (argc == 3) {
            if (strcmp(argv[1], "decimate") == 0) {
                  int d = atoi(argv[2]);
                  if (d <= 0) {
                        Tcl_AppendResult(tcl.interp(),
                              "%s: divide by zero",
                              argv[0], 0);
                        return TCL_ERROR;
                  }
                  if (d != decimate_) {
                        decimate_ = d;
                        setsize();
                  }
                  return (TCL_OK);
            } else if (strcmp(argv[1], "port") == 0) {
                  capwin_->port(argv[2]);
                  return (TCL_OK);
            } else if (strcmp(argv[1], "contrast") == 0) {
                  capwin_->contrast(atoi(argv[2]));
                  return (TCL_OK);
            } else if (strcmp(argv[1], "brightness") == 0) {
                  capwin_->brightness(atoi(argv[2]));
                  return (TCL_OK);
            } else if (strcmp(argv[1], "hue") == 0) {
                  capwin_->hue(atoi(argv[2]));
                  return (TCL_OK);
            } else if (strcmp(argv[1], "saturation") == 0) {
                  capwin_->saturation(atoi(argv[2]));
                  return (TCL_OK);
            } else if (strcmp(argv[1], "create-capwin") == 0) {
                  /*XXX port*/
                  capwin_ = new PlxWindow(argv[2], &vinfo_, PLX_INPUT_0);
                  tcl.result(capwin_->name());
                  return (TCL_OK);
            }
      }
      return (Grabber::command(argc, argv));
}

Plx422Grabber::Plx422Grabber() : image_(0), converter_(0)
{
}

Plx422Grabber::~Plx422Grabber()
{
      delete[] image_;
}

void Plx422Grabber::capture()
{
      /*
       * Grab the frame.
       */
      sigset_t ss;
      capwin_->freeze_frame(&ss);
      Tk_Window tk = capwin_->tkwin();
      /*
       * The parallax X server doesn't seem to support xshmgetimage.
       */
      XImage* image = image_->ximage();
#ifdef USE_SHM
      if (image->obdata != 0)
            XShmGetImage(Tk_Display(tk), Tk_WindowId(tk), image,
                       0, 0, AllPlanes);
      else
#endif
            XGetSubImage(Tk_Display(tk), Tk_WindowId(tk),
                       0, 0, image->width, image->height,
                       AllPlanes, ZPixmap, image, 0, 0);
      capwin_->release_frame(&ss);
      converter_->convert((u_int8_t*)image->data,
                      image->width, image->height, frame_);
}

void Plx422Grabber::setsize()
{
      int w = capwin_->basewidth() / decimate_;
      int h = capwin_->baseheight() / decimate_;
      capwin_->setsize(w, h);
      converter_ = RGB_Converter_422::instance();
      image_ = StandardVideoImage::allocate(capwin_->tkwin(), w, h);
      set_size_422(w, h);
      allocref();
}

int Plx422Grabber::grab()
{
      capture();
      suppress(frame_);
      saveblks(frame_);
      YuvFrame f(media_ts(), frame_, crvec_, outw_, outh_);
      return (target_->consume(&f));
}

void Plx411Grabber::setsize()
{
      int w = capwin_->basewidth() / decimate_;
      int h = capwin_->baseheight() / decimate_;
      capwin_->setsize(w, h);
      converter_ = RGB_Converter_411::instance();
      image_ = StandardVideoImage::allocate(capwin_->tkwin(), w, h);
      set_size_411(w, h);
      allocref();
}

void PlxCIFGrabber::setsize()
{
      int w = 2 * 352 / decimate_;
      int h = 2 * 288 / decimate_;
      capwin_->setsize(w, h);
      converter_ = RGB_Converter_411::instance();
      image_ = StandardVideoImage::allocate(capwin_->tkwin(), w, h);
      set_size_411(w, h);
      allocref();
}

PlxJpegGrabber::PlxJpegGrabber() : q_(50), cimage_(0)
{
}

PlxJpegGrabber::~PlxJpegGrabber()
{
      /*XXX free cimage_ */
}

void PlxJpegGrabber::setsize()
{
      int w = capwin_->basewidth() / decimate_;
      int h = capwin_->baseheight() / decimate_;
      capwin_->setsize(w, h);
      inw_ = outw_ = w;
      inh_ = outh_ = h;
#ifdef notdef
      Tk_Window tk = capwin_->tkwin();
      if (cimage_ != 0)
            (void)XPlxDestroyCImage(cimage_);
      cimage_ = XPlxCreateCImage(Tk_Display(tk), DATA, SIZE, w, h);
#endif
}

int PlxJpegGrabber::capture(u_int8_t* bp)
{
      sigset_t ss;
      capwin_->freeze_frame(&ss);
      XPlxCImage* p;
      Tk_Window tk = capwin_->tkwin();
      int w = capwin_->width();
      int h = capwin_->height();
#ifdef USE_SHM_notyet
      p = cimage_;
      XPlxShmGetCImage(Tk_Display(tk), Tk_WindowId(tk),
                   capwin_->gc(), cimage_, 0, 0, w, h);
#else
      p = XPlxGetCImage(Tk_Display(tk), Tk_WindowId(tk),
                    capwin_->gc(), 0, 0, w, h, w, h);
#endif
      capwin_->release_frame(&ss);
      /*XXX*/
      memcpy(bp, p->data, p->size);
      int size = p->size;

#ifndef USE_SHM_notyet
      XPlxDestroyCImage(p);
#endif

      return (size);
}

int PlxJpegGrabber::grab()
{
      /*
       * Make sure the previous frame has been completely transmitted
       * before we overwrite the buffer.
       */
      tx_->flush();
      /*XXX*/
      static u_int32_t wrk[80*1024 / 4];
      int len = capture((u_int8_t*)wrk);

      JpegFrame f(media_ts(), (u_int8_t*)wrk, len, q_, 0, outw_, outh_);
      return (target_->consume(&f));
}

int PlxJpegGrabber::command(int argc, const char* const *argv)
{
      if (argc == 3) {
            if (strcmp(argv[1], "q") == 0) {
                  /* assume value is in range */
                  q_ = atoi(argv[2]);
                  capwin_->setq(q_);
                  return (TCL_OK);
            }
      }
      return (PlxGrabber::command(argc, argv));
}

Generated by  Doxygen 1.6.0   Back to index