/* From oka@nanotsu.kobe-u.ac.jp Tue Jan 6 20:20:43 1998 Date: Mon, 27 Oct 1997 11:32:03 +0900 From: Koji OKAMURA To: Gerd Knorr , Werner Almesberger , alan@lxorguk.ukuu.org.uk, rjkm@thp.uni-koeln.de, chandran@lrc.di.epfl.ch Subject: Current grabber-bttv.cc [The following text is in the "ISO-2022-JP" character set] [Your display is set for the "ISO-8859-1" character set] [Some characters may be displayed incorrectly] Hi, all, Grabber-bttv.cc has been updated by Gerd's advise. Im' going to modify to capture with interlace off, when encoded by H.261 on NTSC Video. -- Koji */ /* ========================================================================= Copyright (c) 1997 Regents of Koji OKAMURA, oka@kobe-u.ac.jp All rights reserved. Advised by Gerd Knorr ========================================================================= */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #if defined(__linux__) #include #include #endif } #include "grabber.h" #include "vic_tcl.h" #include "device-input.h" #include "module.h" #define NTSC_WIDTH 320 #define NTSC_HEIGHT 240 #define PAL_WIDTH 384 #define PAL_HEIGHT 288 #define CIF_WIDTH 352 #define CIF_HEIGHT 288 #define CF_422 0 #define CF_411 1 #define CF_CIF 2 class BTTVGrabber : public Grabber { public: BTTVGrabber(const char * cformat); virtual ~BTTVGrabber(); virtual void start(); struct bttv_window wtw_; int format_; protected: virtual int command(int argc, const char*const* argv); virtual int grab(); virtual void BTTVgrab(); virtual void format(); virtual void setsize(); int fd; unsigned char *tm_; u_int basewidth_; u_int baseheight_; u_int decimate_; int cformat_; int port_; }; class BTTVDevice : public InputDevice { public: BTTVDevice(const char*); virtual int command(int argc, const char*const* argv); }; static BTTVDevice BTTV_device("bttv"); BTTVDevice::BTTVDevice(const char* name) : InputDevice(name) { if(access("/dev/bttv",R_OK) == 0) { attributes_ = " \ format { 411 422 } \ size { small cif large } \ port { TV Port-1 Port-2 S-Video}"; } else attributes_ = "disabled"; } int BTTVDevice::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 3) { if (strcmp(argv[1], "open") == 0) { TclObject* o = 0; o = new BTTVGrabber(argv[2]); if (o != 0) tcl.result(o->name()); return (TCL_OK); } } return (InputDevice::command(argc, argv)); } BTTVGrabber::BTTVGrabber(const char *cformat) { fd=open("/dev/bttv",O_RDWR); if(fd<0){ fprintf(stderr,"open failed: %s %s \n", "/dev/bttv",strerror(errno)); exit(1); } if(!strcmp(cformat, "422")) cformat_ = CF_422; if(!strcmp(cformat, "cif")) cformat_ = CF_CIF; decimate_ =2; basewidth_ = CIF_WIDTH*decimate_; baseheight_= CIF_HEIGHT*decimate_; if(ioctl(fd, BTTV_GETWTW, &wtw_)){ perror("ioctl:BTTV_GETWTW"); exit(1); } wtw_.color_fmt = BT848_COLOR_FMT_YUY2; wtw_.bpp =2; wtw_.width = basewidth_ /decimate_; wtw_.height= baseheight_/decimate_; wtw_.bpl = wtw_.width*wtw_.bpp; if(!wtw_.norm) wtw_.interlace = ((wtw_.width > PAL_WIDTH) || (wtw_.height > PAL_HEIGHT)) ? 1:0; else wtw_.interlace = ((wtw_.width > NTSC_WIDTH) || (wtw_.height > NTSC_HEIGHT)) ? 1:0; /* wtw_.norm = 0; */ if(ioctl(fd, BTTV_SETWTW, &wtw_)){ perror("ioctl:BTTV_SETWTW"); exit(1); } tm_ =(unchar *)malloc(0x200000); if (tm_==NULL) { printf("Cannot alloc memory\n"); exit(1); } #ifndef BTTV_DONT_MLOCK if (-1 == mlock(tm_, 0x200000)) { perror("mlock"); /* DANGER: we continue and hope touch-every-page before grab is enouth... */ /* exit(1); */ } #endif port_=0; ioctl(fd, BTTV_INPUT, &port_); } BTTVGrabber::~BTTVGrabber() { #ifndef BTTV_DONT_MLOCK if (-1 == munlock(tm_, 0x200000)) perror("munlock"); #endif free(tm_); close(fd); } void BTTVGrabber::start() { format(); Grabber::start(); } int BTTVGrabber::command(int argc, const char*const* argv) { if (argc == 3) { if (strcmp(argv[1], "decimate") == 0) { int dec = atoi(argv[2]); Tcl& tcl = Tcl::instance(); if (dec <= 0) { tcl.resultf("%s: divide by zero", argv[0]); return (TCL_ERROR); } if (dec != decimate_) { decimate_ = dec; wtw_.width = basewidth_ /decimate_; wtw_.height= baseheight_/decimate_; wtw_.bpl = wtw_.width*wtw_.bpp; if(!wtw_.norm) wtw_.interlace = ((wtw_.width > PAL_WIDTH) || (wtw_.height > PAL_HEIGHT)) ? 1:0; else wtw_.interlace = ((wtw_.width > NTSC_WIDTH) || (wtw_.height > NTSC_HEIGHT)) ? 1:0; if(ioctl(fd, BTTV_SETWTW, &wtw_)){ perror("ioctl:BTTV_SETWTW"); exit(1); } setsize(); } }else if (strcmp(argv[1], "port") == 0) { int p = port_; if(!strcmp(argv[2], "TV")) p = 0; if(!strcmp(argv[2], "Port-1")) p = 1; if(!strcmp(argv[2], "Port-2")) p = 2; if(!strcmp(argv[2], "S-Video"))p = 3; if (p != port_) { port_ = p; ioctl(fd, BTTV_INPUT, &port_); } return (TCL_OK); /* }else if (strcmp(argv[1], "norm") == 0) { int n = wtw_.norm; if(!strcmp(argv[2], "PAL")) n = 0; if(!strcmp(argv[2], "NTSC")) n = 1; if (n != wtw_.norm) { wtw_.norm = n; if(ioctl(fd, BTTV_SETWTW, &wtw_)){ perror("ioctl:BTTV_SETWTW"); exit(1); } } return (TCL_OK); */ } else if (strcmp(argv[1], "format") == 0) { if (running_) format(); return (TCL_OK); } else if (strcmp(argv[1], "contrast") == 0) { contrast(atof(argv[2])); return (TCL_OK); } } return (Grabber::command(argc, argv)); } void BTTVGrabber::BTTVgrab() { int i,j, yy, uv; int n=0; unsigned char *y,*u,*v; for (i=0; i<0x200000; i+=4096) tm_[i]=1; tm_[0x1fffff]=1; ioctl(fd, BTTV_TESTM, &tm_); y=frame_; u=frame_+outh_*outw_; if(cformat_ == CF_422) v=u+outh_*outw_/2; else v=u+outh_*outw_/4; for(i=0;iconsume(&f)); } void BTTVGrabber::setsize() { switch(cformat_){ case CF_422: set_size_422(basewidth_ / decimate_, baseheight_ / decimate_); break; case CF_CIF: set_size_411(basewidth_ / decimate_, baseheight_ / decimate_); break; } allocref(); } void BTTVGrabber::format() { if(wtw_.norm){ baseheight_ = NTSC_HEIGHT * 2; basewidth_ = NTSC_WIDTH * 2; }else{ baseheight_ = PAL_HEIGHT * 2; basewidth_ = PAL_WIDTH * 2; } if(cformat_ == CF_CIF) { baseheight_ = CIF_HEIGHT * 2; basewidth_ = CIF_WIDTH * 2; } wtw_.width = basewidth_ /decimate_; wtw_.height= baseheight_/decimate_; wtw_.bpl = wtw_.width*wtw_.bpp; if(!wtw_.norm) wtw_.interlace = ((wtw_.width > PAL_WIDTH) || (wtw_.height > PAL_HEIGHT)) ? 1:0; else wtw_.interlace = ((wtw_.width > NTSC_WIDTH) || (wtw_.height > NTSC_HEIGHT)) ? 1:0; if(ioctl(fd, BTTV_SETWTW, &wtw_)){ perror("ioctl:BTTV_SETWTW"); exit(1); } setsize(); }