Frame Grabber pro Linux - navod na udelani _LONG_ (prominte, ale zdalo se mi to zajimave)

Jaroslav Lukesh lukesh na seznam.cz
Středa Srpen 18 08:21:58 CEST 1999


> potrebuji nutne nejaky Frame Grabber pro Linux.
> 
> Nejradeji bez TV tuneru a podobnejch 
> zbytecnosti a nejlepe s nekolika videovstupy.
> 
> Z grabberu podporovanych jaderm 2.2.x se mi 
> nejvice zamlouva 'Matrix Vision delta'
> (sympaticka mala karta se ctyrmi vstupy). 
> 
> Bohuzel ani pro tento ani pro zadny jiny grabber
> (krome AVerMedia , ktere obsahuji TV tunery,
> surround a podobny zbytecnosti) se mi nepodarilo
> nikde najit ceskeho prodejce.
> 
> Netusite nekdo kde to sehnat ???

To netusim, ale ja bych si ho udelal sam. Napriklad cernobily s naklady pod
100Kc i s konektory vypada asi takto. Docela bomba, ze?
(sorry, nemam URL, jen tento text kdysi stazeny z nejake BBS)

Happy bastling!



             Jaroslav Lukesh, K-net

--------------------------------------------------
               http://www.k-net.cz
      Multimedia, Networking, Communications
              Windows terminals, NC
         computer hardware and software
--------------------------------------------------


                                       Dirt Cheap Frame Grabber V2.03
                         by Michael Day
                        as of 8 Feb 1992
                         public domain

    (DB25P)                                     
    DO0 ---330ohm-------------*--->|--*-->|---*    IC1 = LM339   
    pin 2                  Vr |  red    1N914 |          quad    
                       (2.4v) |  led          |        comparator
    DO1 ---330ohm-------------*               |                   
    pin 3                     |               |    * = connection    
                             330ohm           |                       
          1N914               |               |    ) = no connect
    DO6 ---|<---*---1Kohm-----* Vc (2.21v)    |       (jump over)
    pin 8                     |               | 
          1N914               |               | Vr = ref voltage  
    DO7 ---|<---*---510ohm----*------*        |      2.4 volts        
    pin 9                     |      |        |                   
                   (trimmer) 5Kohm<--*        | Vc = 00 = 1.65v   
                              |               |      01 = 1.80v   
    DO2 ----------*-----------)------| |------*      10 = 1.95v   
    pin 4         |           |     .1uf      |      11 = 2.21v   
                 3|           |               |                       
    DC3           |/ |6       |               | Vz = 00 = 0.74v   
    (slct)     1 /  -|--------* Vz (1.0v)     |      01 = 0.81v   
    DS6 --------|IC1a|        |               |      10 = 0.88v   
    (ack)        \  +|----*   |               |      11 = 1.00v   
    pins 10,17     \ |7   |  360ohm           |                     
                          |   |               | Vy = 00 = 0.45v   
    DC2            / |4   |   |               |      01 = 0.54v     
    (init)     2 /  -|----)---* Vy (0.66v)    |      10 = 0.59v   
    DS5 --------|IC1b|    |   |               |      11 = 0.66v    
    (pe)         \  +|----*   |               |                   
    pins 12,16     \ |5   |  220ohm           | Vx = 00 = 0.34v   
                          |   |               |      01 = 0.37v        
    DC1            / |10  |   |               |      10 = 0.40v   
    (afd)     13 /  -|----)---* Vx (0.45v)    |      11 = 0.45v   
    DS4 --------|IC1c|    |   |               |                   
    (slct)       \  +|----*   |               | Vs = 00 = 0.086v  
    pins 13,14     \ |11  |  360ohm           |      01 = 0.093v  
                          |   |               |      10 = 0.101v  
    DC0            / |8   |   |               |      11 = 0.115v  
    (stb)     14 /  -|----)---* Vs (0.12v)    |  Assumes Vz set
    DS7 --------|IC1d|    |   |               |  for 1.0v using 
    (busy)       \  +|----*   |               |  5Kohm trimmer 
    pins 11,1   12|\ |9   |  120ohm           |  with DO6, DO7 
                  |       |   |               |  set high.      
    Gnd ----------*-------)---*---------------*------*--------*
    pins                  |   |               |      |        |
    18,19,20,21,          |  100Kohm          |     75ohm     |
    22,23,24,25           |   |      .1uf     |      |        |
                          *---*-------| |-----)------*------o )          
                   2N2222 |                   |             RCA   
            *---------C   E                   |            phono
            |           B                     |            jack 
    pin 5   |           |      1N914          | 
    DO3 ----*--4.7Kohm--*-------->|-----------*

To make it all work, simply plug the connector into a printer 
port on the PC, and run the frame grabber program. When running 
the program, the LED should turn on. That indicates that the 
circuit has enough power to operate. If the LED does not come on, 
or it is very dim, there may not be enough power, and you can't 
use that printer port with the circuit. Try another port or a 
different computer. Note that you may see some minor flickering 
on the led when changing the DO6 and DO7 data output lines. This 
is normal and indicates that the circuit is working properly. 

Changing the DO6 and DO7 data output lines causes the current 
flow through the voltage reference ladder to change. This means 
that more or less current will be available to the LED, causing 
it to change in brightness. The LED should not go out completely 
nor become very dim. That would indicate that there is not enough 
power available to drive the voltage reference or a problem in 
your program.

You can operate in the simple mode by outputting a 0FFH to the 
data output port which sets all the output lines high. This 
provides power to the comparators, voltage reference, and clamp 
transistor. It also disables the gray scale control lines. 

To shift the gray scale reference voltage level, send either a 
03FH (gray ref 0), 07FH (gray ref 1), 0BFH (gray ref 2), or 0FFH 
(gray ref 3) to the data output port. 

The resulting detected output from the port is as follows:

    76543210
    1000xxxx  sync
    0000xxxx  level 0 (black)
    0001xxxx  level 1 (dark gray)
    0011xxxx  level 2 (gray)
    0111xxxx  level 3 (white)
    
Note that bits 0-3 are unknown and should not be relied on as 
being valid.


Video Data Translation:

Once I get the data, I convert it to an intermediate form to be 
stored in the interpretation array. This array keeps the gray 
level values collected on the previous frames. The display 
routine will later interpret the values stored in the 
interpretation array into an absolute gray scale level for each 
display pixel.

The video data is converted by searching for the horizontal sync 
pulse. Once found, we search for the end of the sync pulse. 
Following the end of the sync pulse is the actual video data. 

Each collected byte in the scan line is read and converted to the 
intermediate gray scale level.  There are only four levels 
involved; 00, 01, 10, and 11. Note that since sync is not video 
data, it is not included in the gray scale level. Even if it were 
included, it would be a 00 value. Once converted, the byte is 
then shifted into it's proper frame position in the interpretation 
array byte and stored in the array. 

This is repeated until either the full width of the 
interpretation array is filled, or a new sync pulse is 
encountered. Should a sync pulse be encountered, the rest of the 
interpretation array values are filled with 00. Should the full 
width of the interpretation array be encountered, then the rest 
of the scan line is discarded until an new sync pulse is 
encountered. This sequence is continued until the entire frame 
has been converted.

Each byte is read from the interpretation array 
and translated to an absolute gray level using the translation 
array located in the first 256 bytes of the interpretation array. 
There are 12 levels of gray available, plus black.


Source code:


{Dirt Cheap Frame Grabber - Version 2.03}
{as of 8 Feb 1992 - by Michael Day}
{public domain}

program DCFG2;
uses crt;
const maxframe = 30000;
      maxintrp = 30000;

type frametype = array[0..maxframe] of byte;
     frameptr = ^frametype;
     intrptype = array[0..maxintrp] of byte;
     intrpptr = ^intrptype;
     string8 = string[8];

     FrameObj = object
       fary : array[0..3] of frameptr;
       iary : intrpptr;
       dary : intrpptr;
       inport : word;      {frame port data input address (video data)}
       outport : word;     {frame port data output address (control)}
       frameport : word;   {printer port number to use for frame grabber}
       grabsize : word;    {size of data to grab from port}
       framenum : byte;    {frame sequence number}
       IntrpWidth : word;  {width of the intrp array (scan width) }
       IntrpSize : word;   {size of the intrp array (width*lines) }
       Filenum:word;       {next file frame number to use}
       DiskFrameSize:word;
       FrameCount:word;

       constructor Init;
       destructor Done;
       procedure SetFramePort(what:string8);
       function  GrabFrame(inprt,size:word; Fptr:frameptr):boolean;
       function  GrabOne:boolean;
       procedure F2IConvert(Fnum:byte; GSize,IWidth,ISize:word;
                            Iptr:IntrpPtr; Fptr:FramePtr);
       procedure IntrpDisplay(fnum,IWidth,ISize:word; Iptr:IntrpPtr);
       procedure MakeDiskArray(fnum,IWidth,ISize:word;
                                    Iptr:IntrpPtr; Dptr:IntrpPtr);
     end;

var  Frame : FrameObj;
     prnarray : array[0..3] of word absolute $40:$08;
     screen : array[0..65520] of byte absolute $A000:0;

     crtmode : byte absolute $40:$49;
     oldmode : byte;
     i:word;
     ib:byte;
     cx:char;
     mf:file;
     filenum:word;
     showframe : boolean;
     fns:string;
     MovieEnabled:boolean;


{-----------------------------------------------------------}
{     gray level interpretation chart                       }
{                                                           }
{          frame data                                       }
{gray    F3  F2  F1  F0   F3 = frame 3, F2 = frame 2        }
{level:  76  54  32  10   F1 = frame 1, F0 = frame 0        }
{   12:  11  xx  xx  xx   each group of two bits            }
{   11: <11  11  xx  xx   represent the video level         }
{   10: <11 <11  11  xx   for the frame indicated           }
{    9: <11 <11 <11  11                                     }
{    8:  10 <11 <11 <11   xx = any bit pattern              }
{    7: <10  10 <11 <11   <11 = less than 11; (10, 01, 00)  }
{    6: <10 <10  10 <11   <10 = less than 10; (01 or 00)    }
{    5: <10 <10 <10  10   11, 10, 01, or 00 = the indicated }
{    4:  01 <10 <10 <10                absolute bit pattern }
{    3:  00  01 <10 <10                                     }
{    2:  00  00  01 <10   the gray level for the specified  }
{    1:  00  00  00  01   bit pattern is shown at the left  }
{    0:  00  00  00  00                                     }
{-----------------------------------------------------------}
{this array is used to translate from the interpretation    }
{array data into a gray level for display on the screen     }
const IntrpXlat : array[0..255] of byte = (
    0,1,5,9,2,2,5,9,         6,6,6,9,10,10,10,10,
    3,3,5,9,3,3,5,9,         6,6,6,9,10,10,10,10,
    7,7,7,9,7,7,7,9,         7,7,7,9,10,10,10,10,
    11,11,11,11,11,11,11,11, 11,11,11,11,11,11,11,11,
    4,4,5,9,4,4,5,9,         6,6,6,9,10,10,10,10,
    4,4,5,9,4,4,5,9,         6,6,6,9,10,10,10,10,
    7,7,7,9,7,7,7,9,         7,7,7,9,10,10,10,10,
    11,11,11,11,11,11,11,11, 11,11,11,11,11,11,11,11,
    8,8,8,9,8,8,8,9,         8,8,8,9,10,10,10,10,
    8,8,8,9,8,8,8,9,         8,8,8,9,10,10,10,10,
    8,8,8,9,8,8,8,9,         8,8,8,9,10,10,10,10,
    11,11,11,11,11,11,11,11, 11,11,11,11,11,11,11,11,
    12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12,
    12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12,
    12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12,
    12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12);

{-----------------------------------------------------------}


    {grab a chunk of video from inprt size bytes in length into fary}
    function FrameObj.GrabFrame(inprt,size:word; Fptr:frameptr):boolean;
assembler;
     asm
      mov bx,17000      {timeout if we go over 50ms without sync}
      mov dx,[inprt]
      les di,[Fptr]     {now collect a frame}
      mov cx,0

     @vsloop1:
      mov ah,8 {[vsyncslice]}  {if we are in a vert sync, get out of it
first}
     @vsloop2:
      dec bx
      jz @vdone
      in al,dx
      shl al,1
      jc @vsloop1
      dec ah
      jnz @vsloop2

     @vsloop3:
      mov ah,8 {[vsyncslice]}  {find the start of a vert sync}
     @vsloop4:
      dec bx
      jz @vdone
      in al,dx
      shl al,1
      jnc @vsloop3
      dec ah
      jnz @vsloop4

      cld
      mov cx,[size]      {start collecting data}
      rep
      db 6ch

     @vdone:
      xor al,al        {return error code}
      or bh,bl         {one = all ok}
      jz @vexit        {zero = no sync}
      inc al
     @vexit:
    end;


  Constructor FrameObj.Init;
  var i:byte;
  begin

    for i := 0 to 3 do
    begin
      new(fary[i]);
      fillchar(fary[i]^,sizeof(fary[i]^),0);
    end;
    new(iary);
    fillchar(iary^,sizeof(iary^),0);
    move(IntrpXlat,iary^,256);
    new(dary);
    fillchar(dary^,sizeof(dary^),0);
    move(IntrpXlat,dary^,256);
  end;


  Destructor FrameObj.Done;
  var i:byte;
  begin
    for i := 0 to 3 do
    begin
      dispose(fary[i]);
    end;
    dispose(iary);
    dispose(dary);
  end;


  procedure FrameObj.SetFramePort(what:string8);
  begin
    frameport := 0;
    if length(what) > 0 then
    begin
      case what[1] of
       '2': frameport := 1;
       '3': frameport := 2;
       '4': frameport := 3;
      end;
    end;
    outport := prnarray[frameport]; {- $378}  {get port base addr}
    inport := outport+1;    {- $379}

    port[outport+2] := $04; {- $37A}   {init output control lines}
    port[outport] := $ff;    {init data lines}
    grabsize := 20000;           {default grab size}
    framenum := 0;
    IntrpWidth := 70;
    IntrpSize := IntrpWidth*(262-12);
    framecount := 0;
   end;



  function FrameObj.GrabOne:boolean;
  var Fptr : framePtr;
  begin
    inc(framenum);
    framenum := framenum and 3;
    port[frame.outport] := (framenum shl 6) or $3f;
    Fptr := fary[framenum];
    asm CLI; end;
    GrabOne := GrabFrame(inport,grabsize,Fptr);
    asm STI; end;
    port[frame.outport] := $3f;
  end;



   {==================================================================}
   {note: this assumes that the frame grab array has been preformated}
   {with starting with a valid scan line at the top of the screen}
   procedure FrameObj.F2Iconvert(Fnum:byte; GSize,IWidth,ISize:word;
                                 Iptr:IntrpPtr; Fptr:FramePtr);
   var Bottom:word;
   begin
     asm
       cld
       mov cl,ss:[Fnum]      {get gray scale frame number}
       and cl,03H
       add cl,cl             {*2 = shifter count}
       mov ch,0FCH           {create intrp data mask}
       rol ch,cl
       mov dx,ss:[GSize]     {get size of grabbed data to convert}
       inc dx
       les di,ss:[Iptr]      {get intrp array pointer}
       add di,256            {first 256 bytes has xlat array}
       mov ax,di
       add ax,ss:[ISize]     {compute intrp bottom address offset}
       mov ss:[Bottom],ax    {and save it}
       mov bx,ss:[IWidth]    {put intrp right edge offset into bx}

       push ds               {save current data segment}
       lds si,ss:[Fptr]      {get video frame pointer to DS:SI}
       add si,500            {ignore the vertical sync}

     {data conversion loop starts here}
     @loop1:
       dec dx           {did we run out of data?}
       jz @done
       lodsb            {get a frame scan byte}
       shl al,1         {if it is a sync, try again}
       jc @loop1

     @loop2:
       dec dx           {did we run out of data?}
       jz @done
       lodsb            {get a frame scan byte}
       shl al,1         {if it is a sync, we are}
       jc @loop4        {done with the scan line}

       {convert scan input data to intrp level reference}
       xor ah,ah        {init to zero level}
       shl al,1         {if highest level on}
       adc ah,0         {add one to level count}
       shl al,1         {if next high level on}
       adc ah,0         {add one to level count}
       shl al,1         {if lowest level on}
       adc ah,0         {add one to level count}
       shl ah,cl        {adjust result to position}
       mov al,es:[di]   {get current intrp value}
       and al,ch        {strip old intrp value}
       or al,ah         {insert new intrp value}
       mov es:[di],al   {save the new intrp value}
       inc di
       dec bx           {if not at end of intrp line}
       jnz @loop2       {go process the next byte}

     {ran against right edge of intrp window}
     {so throw away rest of the scan data}
     @loop3:            {suck up extra scan data}
       dec dx           {did we run out of data?}
       jz @done
       lodsb            {get a frame scan byte}
       shl al,1         {if it is not a sync, }
       jnc @loop3       {keep looping}
       jmp @loopd

     @loop4:            {fill out rest of intrp data}
       and es:[di],ch   {strip old intrp value to 0}
       inc di
       dec bx           {loop until right edge reached}
       jnz @loop4

     @loopd:
       mov bx,ss:[IWidth]    {restore width to reg BX}
       cmp di,ss:[Bottom]    {are we at bottom?}
       jc @loop1             {do more if not at bottom}

     @done:
       pop ds             {restore DS and we are done}
     end;
   end;


{=====================================================================}
   {now we are gonna display the video on the screen}
   procedure FrameObj.IntrpDisplay(fnum,IWidth,ISize:word; Iptr:IntrpPtr);
   var Bottom:word;
   begin
     asm
       cld
       push ds
       lds si,ss:[Iptr]      {get intrp array pointer}
       mov bx,si             {point bx at the start of the array}
       add si,256            {first 256 bytes has intpr array}
       mov ax,ss:[ISize]     {compute intrp bottom address offset}
       add ax,si
       mov ss:[Bottom],ax    {and save it}
       mov ax,0A000h         {point es to the display segment}
       mov es,ax
       mov cx,ss:[IWidth]    {put intrp right edge offset}
       mov di,fnum           {start at top left corner of screen}
       and di,1              {offset by frame number count (even/odd)}
       jz @dlp1
       add si,cx             {use odd scan lines on odd video frames}

     @dlp1:
       push di
     @dlp2:
       lodsb          {get a intrp byte}

       xlat           {translate it to gray scale number}
       stosb          {display it}
       inc di         {skip a display pixel (we get it next time)}
       dec cx         {end of the scan line?}
       jnz @dlp2      {loop until done}
       pop di         {restore original display start offset}
       add di,320     {add display width to it}
       mov cx,ss:[IWidth]  {restore Iwidth to cx}
       add si,cx
       add si,cx           {skip three video scan lines}
       add si,cx
       cmp si,ss:[Bottom]  {are we at the bottom?}
       jc @dlp1            {keep going if not}

     @done:
       pop ds          {ok, we're done}
     end;
   end;


{=====================================================================}
   {now we are gonna display the video on the screen}
   procedure FrameObj.MakeDiskArray(fnum,IWidth,ISize:word;
                                    Iptr:IntrpPtr; Dptr:IntrpPtr);
   var Bottom:word;
   begin
     asm
       cld
       push ds
       lds si,ss:[Iptr]      {get intrp array pointer}
       mov bx,si             {point bx at the start of the array}
       add si,256            {first 256 bytes has intpr array}
       mov ax,ss:[ISize]     {compute intrp bottom address offset}
       add ax,si
       mov ss:[Bottom],ax    {and save it}
       les di,Dptr           {point es:di at the disk array}
       mov cx,ss:[IWidth]    {put intrp right edge offset}
       mov dx,si
       add dx,cx

     @dlp1:
       lodsb          {get a intrp byte}
       xlat           {translate it to gray scale number}
       mov ah,al
       xchg si,dx
       lodsb
       xlat
       xchg ah,al
       xchg si,dx
       stosw          {save it in the array}
       dec cx         {end of the scan line?}
       jnz @dlp1      {loop until done}

     @dlp3:
       mov cx,ss:[IWidth]  {restore Iwidth to cx}
       add si,cx
       add si,cx           {skip three video scan lines}
       add si,cx
       mov dx,si
       add dx,cx
       cmp si,ss:[Bottom]  {are we at the bottom?}
       jc @dlp1            {keep going if not}

     @done:
       pop ds          {ok, we're done}
     end;
   end;


procedure DisplayMovieFrame(DWidth,DSize:word; Dptr:IntrpPtr);
var Bottom:word;
begin
     asm
       cld
       push ds
       lds si,ss:[Dptr]      {get intrp array pointer}
       mov ax,ss:[DSize]     {compute intrp bottom address offset}
       add ax,si
       mov ss:[Bottom],ax    {and save it}
       mov ax,0A000h         {point es to the display segment}
       mov es,ax
       mov di,0
       mov cx,ss:[DWidth]    {put intrp right edge offset}

     @dlp1:
       push di
       rep movsb      {get a movie byte and display it}
       pop di         {restore original display start offset}
       add di,320     {add display width to it}
       mov cx,ss:[DWidth]  {restore Iwidth to cx}
       cmp si,ss:[Bottom]  {are we at the bottom?}
       jc @dlp1            {keep going if not}

     @done:
       pop ds          {ok, we're done}
     end;
end;

{================================================================}
function fstr(W:word):string8;
var s:string8;
begin
  str(W,S);
  fstr := S;
end;


{------------------------------------------------------------}
{format of disk file is:                                     }
{       number of frames : word                              }
{    frame size in bytes : word                              }
{   frame width in bytes : word                              }
{       video frame data : array[0..frames] of dary^         }
{------------------------------------------------------------}
procedure OpenMovie;
var MovieWidth : word;
    MovieSize  : word;
    MovieCount : word;
begin
  Frame.FrameCount := 0;
  if Frame.filenum > 9 then frame.filenum := 0;
  MovieWidth := Frame.IntrpWidth*2;
  MovieSize := (Frame.IntrpSize*2) div 3;
  MovieCount := Frame.Framecount;
  fns := 'DCFG'+fstr(Frame.filenum)+'.MOV';
  Assign(mf,fns);
  inc(Frame.filenum);
  rewrite(mf,1);
  blockwrite(mf,MovieCount,2);
  blockwrite(mf,MovieSize,2);
  blockwrite(mf,MovieWidth,2);
end;
procedure WriteMovie;
var MovieSize:word;
begin
  MovieSize := (Frame.IntrpSize*2) div 3;
  inc(frame.framecount);
  Frame.MakeDiskArray(Frame.framenum,Frame.IntrpWidth,
                      Frame.IntrpSize, Frame.Iary, Frame.Dary);
  blockwrite(mf,Frame.Dary^,MovieSize);
end;
procedure CloseMovie;
begin
  reset(mf,1);
  dec(Frame.FrameCount);
  blockwrite(mf,Frame.framecount,2);
  close(mf);
end;

procedure ShowMovie(what:char; Rep:boolean);
var MovieWidth:word;
    MovieSize:word;
    MovieCount:word;
    done:boolean;
begin
  showframe := false;
  done := false;
  While not(done) do
  begin
    if not(Rep) then fns := 'DCFG'+what+'.MOV';
    Assign(mf,fns);
    reset(mf,1);
    blockread(mf,MovieCount,2);
    blockread(mf,MovieSize,2);
    blockread(mf,MovieWidth,2);
    inc(MovieCount);
    i := 0;
    while i < MovieCount do
    begin
      blockread(mf,Frame.Dary^,MovieSize);
      DisplayMovieFrame(MovieWidth,MovieSize,Frame.Dary);
      if keypressed then i := MovieCount;
      gotoxy(1,24);
      write('Showing Movie:',fns,' Frame:',i,' ');
      inc(i);
      delay(50);
    end;
    close(mf);
    if not(Rep) then done := true;
    if keypressed then done := true;
  end;
  gotoxy(1,24);
  write('                                  ');
end;


procedure SaveToFrame;
begin
  OpenMovie;
  WriteMovie;
  CloseMovie;
end;


{ ************************************************************** }
{ program start }

begin
   writeln;
   cx := #255;
   filenum := 0;
   showframe := true;
   MovieEnabled := false;

   directvideo := false;

   OldMode := CrtMode;
   asm
     mov ax,$0013    {switch to vga graphics mode}
     mov bx,0
     int $10
   end;

   ib := 0;
   while ib < 15 do    {load palettes with gray levels}
   begin
     asm
       mov ax,1010h
       mov ch,[ib]      {green}
       add ch,ch
       add ch,ch
       mov cl,ch      {blue}
       mov dh,ch      {red}
       mov bl,[ib]
       mov bh,0
       int 10h
     end;
     inc(ib);
   end;

   fillchar(screen,sizeof(screen),0);


   Frame.Init;
   if ParamCount > 0 then
     Frame.SetFramePort(ParamStr(1))
   else
     Frame.SetFramePort('1');

   gotoxy(1,20);
   write('X:',Frame.IntrpWidth * 2,' Y:',Frame.IntrpSize div
(Frame.Intrpwidth *2),'   ');

 repeat
   if Frame.GrabOne then
   begin
      Frame.F2Iconvert(Frame.Framenum,Frame.GrabSize,
                       Frame.IntrpWidth,Frame.IntrpSize,
                       Frame.Iary, Frame.Fary[Frame.framenum]);

     if MovieEnabled then
     begin
       WriteMovie;
       gotoxy(1,24);
       write('Movie:',fns,' Frame:',Frame.framecount,'  ');
       gotoxy(1,25);
       write('Movie on  ');
     end
     else
     begin
       gotoxy(1,25);
       write('Movie off ');
     end;
     gotoxy(1,22);
     write('          ');

   end
   else
   begin
     gotoxy(1,22);
     write('Lost Sync');
   end;

   if ShowFrame then
     Frame.IntrpDisplay(Frame.framenum,Frame.IntrpWidth,
                        Frame.IntrpSize,Frame.Iary);


   if keypressed then   {key pressed? If so, process it}
        begin
          cx := readkey;
          if cx = #0 then cx := char($80+ord(readkey));
          if MovieEnabled then
          begin
            MovieEnabled := false;
            CloseMovie;
          end;

               if upcase(cx) = 'F'then SaveToFrame
          else if upcase(cx) = 'M' then begin OpenMovie; MovieEnabled :=
true; end
          else if upcase(cx) = 'R' then ShowMovie(cx,true)
          else if upcase(cx) = 'S' then Showframe := false
          else if (cx >= '0') and (cx <= '9') then ShowMovie(cx,false)
          else showframe := true;

          gotoxy(1,20);
          write('X:',Frame.IntrpWidth * 2,' Y:',Frame.IntrpSize div
(Frame.Intrpwidth *2),'   ');
        end;

   until cx < #32;

   asm
     mov ah,$00        {restore original display mode}
     mov al,[oldmode]
     mov bx,0
     int $10
   end;

end.


-----------------------------------------------------------------


                       Program Description

This program requires a 286 or better computer. A printer port 
with the attached device described above with a video signal 
driving it. And a MCGA or VGA type display system. You start the 
program up by entering its name at the DOS prompt followed by the 
printer port number you wish to use. 

Examples: DCFG2 1    <-- loads program for use with LPT1.
          DCFG2 2    <-- loads program for use with LPT2.

If you don't give it a number, the program will default to LPT1. 


Grabbing a Frame:

The program works by grabbing samples from the printer port in 
frames. Once each time through the loop, it sucks in a video 
frame from the video input.  

Actually, more than a frame is grabbed. How much is grabbed 
depends on the speed of access to the printer port on your 
computer. On a typical computer this is 1.5us per byte. At the 
1.5us access rate, 63.5us per scan line, and 265.5 scan lines per 
video frame, that results in 11240 bytes per frame required to be 
collected. The collection size is currently set to 20,000 bytes. 
That provides enough space to handle buss speeds up to 12MHz which 
should be adequate for most computers. 

The down side is that we collect 210 extra scan lines on a normal 
computer. In most situations this isn't a problem since three to 
four frames will typically be lost while the collected video data 
is being processed anyway. The extra partial frame has only a
slight effect on the over all collection time and results. The 
effect is minimized on a fast machine since nearly the entire 
array is filled anyway.

The maximum sample size allowed is 65520. More than that and we 
run out of segment space in memory. Also during this period I 
keep the system interrupts off so as to not have distortions of 
the collected data caused by the system deciding to go off and do 
something else.

In addition to the collection time, there is a pre-configure time 
while the loop is waiting for the vertical sync pulse to come in. 
I don't collect any data prior to the vertical sync pulse since 
it would be ignored anyway. 

The vertical sync is determined by watching the sync line. When 
it goes on for longer than 10us, you are in the vertical sync 
time. Less then 10us, and it is a horizontal sync pulse. 

Once the video data is collected, I release the interrupts to 
allow the computer to return to normal operation. Should no sync
come in during the vertical sync detection period, I terminate 
the loop after a while to allow the computer to continue to 
operate, and return an error condition so that the program will 
know that no data was collected. 

If you have an O'scope, you can verify the video collection time 
by observing data output line DO7 (pin 9). This line should never 
go high for longer than 50ms. Typically it should be around 20 to 
40ms in length. This should be the same whether you have a signal 
going into the video line or not. Though there may be a 
difference between the timing when a signal is present verses 
when it is not present.




Další informace o konferenci Linux