[sci.electronics] DAK Video Digitizer....

tj@XN.LL.MIT.EDU (Thomas E. Jones) (04/09/90)

I just purchased the Video Digitizer from DAK ($169.00.)  It is a
256x256 64-grey level frame grabber.  It comes with 3 programs to
allow you to display images from your camera (or VTR,) make a slide-show
of pictures, and a paint-like program.

None of the software packages let you get the full 256X256 grey-level
image, they all do dithering and reduce the effective resolution.  I
am trying to dis-assemble one of the programs to figure out how to
read from the card myself, but it's fairly difficult and time-consuming.

Does anyone else have one of these systems?  If so, I'd like to share
information with them.  I have figured out a great deal about the card
(both from program disassembly and examination of the hardware.)  Please
get ahold of me.  Anyone who helps out will be entitled to all the software
I get finished.

			- tj@xn.ll.mit.edu
			Thomas E. Jones

-- 
tj@xn.ll.mit.edu or tj@ll-xn.arpa          (one of these should work)
Thomas E. Jones, home (617) 924-8326 work (617) 981-5093

nelson@sun.soe.clarkson.edu (Russ Nelson) (04/09/90)

In article <1788@xn.LL.MIT.EDU> tj@XN.LL.MIT.EDU (Thomas E. Jones) writes:

   Does anyone else have one of these systems?  If so, I'd like to share
   information with them.  I have figured out a great deal about the card
   (both from program disassembly and examination of the hardware.)  Please
   get ahold of me.  Anyone who helps out will be entitled to all the software
   I get finished.

Check this program out.  It digitizes continuously, and copies the image to
the VGA screen.  Note that you *must* have a VGA, and the program doesn't
check.  No copies of the frames are kept, although that's pretty simple to
add.  Most of the time is spent copying it to the VGA memory because of all
the wait states (ick).  If you have a few meg of EMS, you could probably
make a cute small movie.

Curiously enough, I got the information on programming it simply by calling
DAK's technical support number.  I didn't even have to plead and beg, they
just offered to send me the technical specs and program fragments!

This is in Turbo C 2.0:

#include <stdio.h>
#include <dos.h>
#include <stdlib.h>

#define VID 0x3ef

/* when reading VID: */

#define HSYNC	0x40
#define	VSYNC	0x80

/* when writing VID: */

#define RDFIOM	0x80

#define ELAYM	0x70
#define DELAYSHF	4
#define	DELAYNOM	0x60

#define	RFSHEN		8
#define	READMODE	4
#define	CAPTURE		2
#define	VCLEAR		1

int their_palette[64*3];
int our_palette[64*3];

/*
 *	Bios function call definitions
 */

#define	BIOS_VIDFN		0x10	/* Video functions */
#define VID_PALETTE		0x10	/* palette access function */
#define PAL_SETPAL		0x00	/* update single palette register */
#define PAL_SETPALBLOCK		0x02	/* update all palette registers */
#define PAL_GETPALBLOCK		0x09	/* read all palette registers */
#define PAL_GETDACBLOCK		0x17	/* read current VGA DAC values */
#define PAL_SETDACBLOCK		0x12	/* set new VGA DAC values */
#define VID_SETPIXEL		0x0C	/* store pixel value */
#define VID_DISPLAY		0x1A	/* video display combination */
#define VID_SUBSYSTEM		0x12	/* video subsystem configuration */

/*
 *	Arguments to the vid_vgapalette and vid_setpalette functions
 */
#define	PAL_SAVE		0	/* Save existing values */
#define	PAL_RESTORE		1	/* Restore saved values */
#define	PAL_SETGREY		2	/* Set greyscale mapping */
#define	PAL_SETLIN		3	/* Set 1:1 mapping (vid_setpalette) */

/*
 *	Routine to map VGA palette registers (256 colour mode)
 *	to and from a greyscale display.
 */
#define BITSPERBYTE		8
#define BITSPERVGACOLOUR	6
				/* no. VGA DAC registers */
#define SIZE_DACS		256
				/* no. distinct greyscale values */
#define NUM_GREY		(1 << BITSPERVGACOLOUR)
				/* no. palette registers that map
				 * to the same greyscale value */
#define GREY_SAME		(SIZE_DACS / NUM_GREY)
				/* no. underlying colours on vga */
#define PRIMARY_COLOURS		3

static void
vid_vgapalette(action)
int	action;
{
    union REGS			regs;
    struct SREGS		sreg;
    static unsigned char	SaveDacs[SIZE_DACS * PRIMARY_COLOURS],
    				*GreyDacs = 0;

    switch(action)
    {
    	case PAL_SAVE:
	    /* Save existing palette */
	    regs.h.ah = VID_PALETTE;
	    regs.h.al = PAL_GETPALBLOCK;
	    regs.x.bx = 0;		/* first palette register */
	    regs.x.cx = SIZE_DACS;	/* read all palette registers */
	    segread(&sreg);
	    sreg.es = sreg.ds;
	    regs.x.dx = (unsigned int) SaveDacs;
	    int86x(BIOS_VIDFN, &regs, &regs, &sreg);
	    break;

	case PAL_RESTORE:
	    /* restore saved palette */
	    regs.h.ah = VID_PALETTE;
	    regs.h.al = PAL_SETDACBLOCK;
	    regs.x.bx = 0;		/* first palette register */
	    regs.x.cx = SIZE_DACS;	/* read all palette registers */
	    segread(&sreg);
	    sreg.es = sreg.ds;
	    regs.x.dx = (unsigned int) SaveDacs;
	    int86x(BIOS_VIDFN, &regs, &regs, &sreg);
	    break;

	case PAL_SETGREY:
	    /* set palette to greyscale */
	    if (GreyDacs == 0)
	    {
		unsigned char	*p;
	    	int		c;

	    	if ((GreyDacs = malloc(SIZE_DACS*PRIMARY_COLOURS))
			== 0)
		{
		    return;
		}
		for (p = GreyDacs, c = 0; c < SIZE_DACS; c++)
		{
		    int		i;

		    for (i = 0; i < PRIMARY_COLOURS; i++)
			*p++ = (c & 0x3f);
		}
	    }
	    regs.h.ah = VID_PALETTE;
	    regs.h.al = PAL_SETDACBLOCK;
	    regs.x.bx = 0;		/* first palette register */
	    regs.x.cx = SIZE_DACS;	/* read all palette registers */
	    segread(&sreg);
	    sreg.es = sreg.ds;
	    regs.x.dx = (unsigned int) GreyDacs;
	    int86x(BIOS_VIDFN, &regs, &regs, &sreg);
	    break;
    }
}

insb(int port, void far *buf, int cnt)
{
	_DX = port;
	_CX = cnt;
	_ES = FP_SEG(buf);
	_DI = FP_OFF(buf);
	__emit__(0xf3, 0x6c);		/* rep insb */
}

video()
{
	int i;

	geninterrupt(0x10);
}

vidinit()
{
	outportb(VID, READMODE | DELAYNOM);
	outportb(VID, VCLEAR | RFSHEN | READMODE | DELAYNOM);
}

main()
{
	int y;

	_AX = 0x13;
	video();

	vid_vgapalette(PAL_SAVE);

	vid_vgapalette(PAL_SETGREY);

	while (!kbhit()) {
		while ((inportb(VID) & VSYNC) == VSYNC)
			if (kbhit())
				break;
		outportb(VID, DELAYNOM | READMODE);
		outportb(VID, VCLEAR | DELAYNOM);
		outportb(VID, VCLEAR | DELAYNOM | CAPTURE);
		while ((inportb(VID) & VSYNC) == 0)
			if (kbhit())
				break;
		while ((inportb(VID) & VSYNC) == VSYNC)
			if (kbhit())
				break;
		outportb(VID, DELAYNOM);
		outportb(VID, READMODE | DELAYNOM | RDFIOM);
		outportb(VID, READMODE | VCLEAR | DELAYNOM | RDFIOM);

		for (y = 0; y < 200; y++) {
			insb(VID, MK_FP(0xa000, y * 320), 256);
		}

		outportb(VID, READMODE | VCLEAR | DELAYNOM);
		vidinit();
	}

	getch();

	vid_vgapalette(PAL_RESTORE);

	_AX = 0x3;
	video();
}
--
--russ (nelson@clutx [.bitnet | .clarkson.edu])  Russ.Nelson@$315.268.6667
Violence never solves problems, it just changes them into more subtle problems

MXP122@psuvm.psu.edu (Zaphod Beeblebrox) (04/10/90)

Yeaperie. . . .

The first 'guess' I made at the format was . . since its 256x256
that amounts to a nice 64K file. . and the file sizes were about half
of this. . so I read in the file byte by byte in a C program. . .
128 bytes across and 256 lines down. . when the first nibble was the
color for the left pixel (16 shades. . ) and the other nibble was the
right pixel. . worked like a charm. . I just let the VID program grab
the images (I tried to disassemble it. .but it was written in a high
level language and the machine code is very messed up). . .I can post
the C file if anyone's interested. . .etc etc. . .


          Mark

bbb@kuhub.cc.ukans.edu (04/10/90)

In article <1788@xn.LL.MIT.EDU>, tj@XN.LL.MIT.EDU (Thomas E. Jones) writes:
> I just purchased the Video Digitizer from DAK ($169.00.)  It is a
> 256x256 64-grey level frame grabber.  It comes with 3 programs to
> allow you to display images from your camera (or VTR,) make a slide-show
> of pictures, and a paint-like program.
> 
> None of the software packages let you get the full 256X256 grey-level
> image, they all do dithering and reduce the effective resolution.  I
> am trying to dis-assemble one of the programs to figure out how to
> read from the card myself, but it's fairly difficult and time-consuming.
> 
> Does anyone else have one of these systems?  If so, I'd like to share
> information with them.  I have figured out a great deal about the card
> (both from program disassembly and examination of the hardware.)  Please
> get ahold of me.  Anyone who helps out will be entitled to all the software
> I get finished.
> 
> 			- tj@xn.ll.mit.edu
> 			Thomas E. Jones
> 
> -- 
> tj@xn.ll.mit.edu or tj@ll-xn.arpa          (one of these should work)
> Thomas E. Jones, home (617) 924-8326 work (617) 981-5093
THOMAS

To answer your questions directed to BROWNRIGG  (I'm his friend with the
DAK card. Just got my account today.)

The card really only appears to digitze about 245 lines @ 256 pix.
The fundamental drivers I got from DAK software support. That number is
in the manual you got with the board. I write all in MS-C and MS-QC.
I have chosen MSQC for my software because is allows in-line assembly.
(QC ver 2.00 that is)  Below is the listing for my so called Super-Vid.
(SVID) It will get about 4-6 frames/sec out to the VGA on a 286. Maybe
more I haven't really tried to measure it.  After that is the .h file I
use.  I saw you got a Turbo-C version. The major difference in my code
is the watching the FRAME bit to make sure successive frames are the same
one. Otherwise you will notice a 'jumping' of the image as it randomly
gets different frames (even-vs-odd) of the interlace.

I'm still looking for info on the Closed-Caption. In theory I should have 
about 33000 Usec between CC info lines and that leads me to think I could
capture that single line, decode it and write it out to screen or file.
Would be neat to be able to generate transcripts of CC programs of interest.


*********************************************************************
     SVID


// modified for `max' transfer speed!!!!! I hope..
// SVID  by  Brett Bennett
// Based orginally on information supplied by DAK
//
// Quick-C ver 2.0  
//
// compile line:   QCL /G2 SVID.C
//
// program uses QC-2 inline assembly to max out transfer from interface
// to VGA memory.  Uses an  INSB  command that is available only on 80286's
// and up.  PROGRAM WILL NOT WORK ON AN 8086/88.  A V-20 does seem to work.
//
// Program may be freely modified and distributed with proper acknowlegdments
//
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include "vid.h"
#include <graph.h>
//#define MAXSAMP 62000l
#define MAXSAMP 51200l
unsigned char huge *buf;
int gain,enlighten,lines;
int max,ofset=20;
unsigned char DELAYNOM=0x00;
unsigned char far *mem;     /* ignore its warnings */
//
//this var is crtical for precise frame grabbing applications.
unsigned char flipflop=0; //controls frame grabbers frame syncing



char key;


main (argc, argv)
int argc;
char * argv[];

{
long count,sum;
int avg;
count=MAXSAMP;
//printf("Enter multiplier factor ");
//scanf("%d",&gain);
//printf("Enter # scanlines");
//scanf("%d",&lines);
lines=200;
ofset=0;


if ( (argc>1)  &&  (0==strcmpi(argv[1],"?")) )
{
printf("\n\n         B&D Electronics  Super VIdeo Display 1990(c)\n\n");
printf("Format:\nSVID ofset lines\n");
printf("Ofset= number of lines to skip\n");
printf("lines= number of lines to display per frame\n");
printf("SVID  w/no parameters defaults to ofset=0, lines=200\n");
printf("Press CR to toggle between frames\n");
printf("Space bar to freeze then again to end\n");
exit(0);
}

if ( argc > 1 ) ofset=atoi(argv[1]);
ofset=ofset*256;

if ( argc > 2 ) lines=atoi(argv[2]);

buf = (char huge *)halloc( count, sizeof( char ) );
if ( buf == 0 ) {printf("allocate failed.\n");exit(1);}

if ( 0 == _setvideomode(_MRES256COLOR)) {
     printf("Sorry  VGA  required.\n");
     exit(0);
     }
//build a 64 shade gray table! 4 times
_disable(); //stop interupts
for (max=0;max<64;max++) {     //
  outp(0x3c8, (char)max);  //VGA's DAC reg 
  outp(0x3c9, (char)max);  //RED
  outp(0x3c9, (char)max);  //GREEN
  outp(0x3c9, (char)max);  //BLUE

  outp(0x3c8, (char)max+64);
  outp(0x3c9, (char)max);
  outp(0x3c9, (char)max);
  outp(0x3c9, (char)max);

  outp(0x3c8, (char)max+128);
  outp(0x3c9, (char)max);
  outp(0x3c9, (char)max);
  outp(0x3c9, (char)max);

  outp(0x3c8, (char)max+192);
  outp(0x3c9, (char)max);
  outp(0x3c9, (char)max);
  outp(0x3c9, (char)max);
}

vidinit();  //init the video card. 

while ( key != 32)   //wait for a space char
{

do
{
// modified ver of vxfer goes directly to video memory.
_disable();
vxfer();
_enable();
}
while ( !kbhit() );

key=getch();
flipflop=!flipflop; //toggle flipflop.  controls which frame of the interlace

}



getch();
_setvideomode(_DEFAULTMODE);
}  //end main






/***********************************************************************/
/*          DRIVING ROUTINES   Original code from DAK                  */
/***********************************************************************/



/* THIS FUNCTION INITIALIZES TME VIDEO BOARD LOGIC */

vidinit()
{
outp(VIDBOARD, DELAYNOM | READMODE); /* clear the board */
outp(VIDBOARD, VCLEAR | RFSHEN | DELAYNOM |  READMODE); /* clear the board */
}

/*******************************************************/

pas() /* this is a wait loop (pause) function */
{
int i;
int j;
for (i=1; i<300;++i)
	for (j=1; j<100;++j );
}


/******************************************************/
/* the CAPTURE FUNCTION FOR OPERATING THE VIDEO CARD  */
/******************************************************/
vxfer()
{
int i;
unsigned int j;
int done;
i = 10000; /* Start by making sure that vertical syncs are occurring */
done = 0;
while ( !done )
	{

//flip-flop var controls what frame to grab.
//while the DAK card doesn't know which frame is the even and which is odd
//(depends on when the video signal was first applied to the card) It does
//keep track of one from the other.  This is critical for accurate capture
//of images. ESP when doing things like R-G-B color seperation work.

// wait for sync high  AND  field bit high.
if( flipflop ) { //waits for high field bit.
		if ( (inp(VIDBOARD) & FVSYNCM) == FVSYNCM) done = 1;
		if (--i < 0) done = 1;
		}

// wait for sync high  AND  field bit low.
if( !flipflop ) {    
		if ( (inp(VIDBOARD) & FVSYNCM) == VSYNCM) done = 1;
		if (--i < 0) done = 1;
		}

	}

if (i < 0)
	{
//	_setvideomode(MTEXT);
	printf("Vertical sync is stuck high..aborting\r");
	pas();
	}
else 
{
i = 10000;
done = 0;
while ( !done )
	{
//NOW WAIT FOR SYNC TO GO LOW. 
	if ( (inp(VIDBOARD) & VSYNCM) == 0) done = 1;
	if (--i < 0) done = 1;
	}
if (i < 1)
	{
//	_setvideomode(MTEXT);
	printf("No vertical sync detected..aborting\r" );
	pas(); i=10000;
	}
else 
{

//ok here we know that vertical syncs are occuring. that is good!
//SYNCH IS LOW AND FIELD IS HIGH TAKE A PICTURE!

//go with what I was given from DAK...

outp(VIDBOARD, DELAYNOM | READMODE); /* clear the board */
outp(VIDBOARD, VCLEAR | DELAYNOM);   /* set board in write mcde */
outp(VIDBOARD, VCLEAR | CAPTURE | DELAYNOM); /* capture */

i = 10000;
while ( ( (inp(VIDBOARD) & VSYNCM) == 0) && (--i > 0) );
					/* while sync present */


//reduce i here is you don't want to wait for a full screens worth.
i = 10000;  //appears to be a sufficently long enough delay.
while ( ( (inp(VIDBOARD) & VSYNCM) == VSYNCM) && (--i > 0) ); /* Wait */


outp(VIDBOARD, DELAYNOM); /* set clear and remove capture */
outp(VIDBOARD, READMODE | DELAYNOM | RDFIOM);

/* With clear set, goto read mode */
outp(VIDBOARD, READMODE | VCLEAR | RDFIOM | DELAYNOM);

{ 
//high speed direct to video memory transfer here.
_disable();       //stop any further system interupts. except NMIs
_asm
{
	push ax       ;save some regs
	push cx
    push dx
	push di
	push es

    mov dx,0x3ef  ;prepare dx for port address
    mov cx,ofset  ;get var OFSET and skip this many lines.
    jcxz noeatum  ;jump cx=zero. if zero then jump to eatum
eatum: in al,dx   ;skip over requested lines. EXPECTED to be 256*#lines.
    loop eatum    ;loop back and eat um up
noeatum:
	mov cx,lines  ;number of lines to do.
    jcxz exitstageleft
    mov ax,0xa000 ;segment of vga memory.
    mov es,ax     ;move segment to es for  INSB  instruction to come.
    mov di,0      ;set inital offset to zero
                  ;regs now prep. time to get the data.
line: push cx     ;save number of lines left to do.
      mov cx,256  ;load number of pixels for next line.
      rep insb    ;do insb  cx times.
      add di,64   ;shift to next line of video 320x200 mode only!
      pop cx      ;get line count back
      loop line   ;back to get next line.

exitstageleft:
      pop es      ;restore regs.
      pop di
      pop dx
      pop cx
      pop ax
}


}
/* now disable DMA request */
//outp(VIDBOARD, READMODE  | VCLEAR | DELAYNOM);
}
}


}//end vxfer




******************************************************************
VID.H


/*  VID.H  taken orginally for  DAK  supplied user info.
Some of the items in their include did not seem to be accurate for this
version of the digitizer. 
Major mode is addition is  FVSYNCM  used to monitor which frame (even/odd)
is taken.
*/ 

/*     DAKS  include. */
/* Vid.d lnclude file Aug. 11, 1987 */
#define MTEXT 1 /* the Video modes */
#define GRAPH 2

/* the VIDEO BOARO DEFS */
#define VIDBOARD 0x3ef

/* the read space */
#define VIDMASK 0x3f /* the 6 Video bit sample */

//#define HSYNCM 0x40 /*horizontal sync mask DOES NOT APPLY TO THIS BOARD!*/
/* low for 5 of each 62.5 usec <- apparently a different board than DAK's*/

#define FSYNCM  0x40 /*the frame sync mask toggles with each vsync field. */

#define VSYNCM  0x80 /*Vertical sync mask high for 180 Usec every 33.3 msec */

#define FVSYNCM 0xc0 /*Frame and Vertical sync mask use to ensure vertical */

/* the write space */

#define RDFIOM   0x80 /* 1 == read frame data via i/o */
#define DELAYM   0x50 /* delay bit mask */
#define RFSHEN   0x08 /*DMA request enable mask *actually enable main-board refreshs**/
#define READMODE 0x04 /* 1 = Read Mode ; 0 = Write mode */
#define CAPTURE  0x02 /* low to hlgh transiticn initiates a capture */
#define VCLEAR   0x01 /* when low, clears the line and pixel counters */

//I like to set these in my code
//#define DELAYSHF 0x04 /* delay bit shlft */
//#define DELAYNOM 0x60 /* nominal delay Value defined in the */