 |
Technote 1
Introduction
The purpose of this document is to support software developers in their efforts to write software for AVIS hardware. It contains a description of the AVIS dataformat and some Pascal sourcecode to show how to analyse the data coming from the AVIS hardware.
This document is not confidential, no non-disclosure aggreement (NDA) needs to be signed. Nevertheless the recipients were chosen according to their qualification, so please do not redistribute this document.
Software developed with the help of this document can be distributed freely, compiled or in sources.
In order to avoid duplicate developments contact us to coordinate efforts.
Any further questions should be directed to
Ponton European Media Art Lab
Benjamin Heidersberger
Lister Strasse 17 - 30163 Hannover, Germany
tel +49-511-627032 - fax +49-511-621799
benjamin@ponton.de
AVIS Dataformat by Christian Wolff Versiondate: 950328-1711
AVIS (Asynchronous Vertical Image Scan) is a method to transmit pictures,
text, and sound for the purpose of picturetelephony on a dataconnection
with 19200 bps (e.g. a 14000-bps modem-connection with compression). There
is a hardware for converting a videosignal into a serial datastream. This
hardware is pluged inbetween the computer and the modem. To switch the
datastreams from computer or from AVIS to the modem and to decode the
incoming picture-data you need a software. Until now this software is
available for DOS, Mac, Amiga, and Windows.
AVIS-Data is transmitted in blocks of variable length. There are two
different types of blocks, a pictureblock and a datablock.
Both are recognised by a sequence of sync-characters.
Pictureblock:
* At least 20 bytes $0F (picturesync)
After receiving the first not-pic-sync you have to decide by the number
of received pic-syncs if the picture is PAL or NTSC: if it was less
than 34 bytes the picture is NTSC, else PAL. You should program a
hysteresis by shifting the border to 33 bytes, if the last picture
was PAL, or 36 bytes, if the last picture was NTSC.
* 1 to 6 bytes of trash, normally 2. For example, if you receive a NTSC
picture with 29 bytes of picsync then you have 3 bytes of trash to
fill the column up to 32 bytes (standard column length for NTSC).
This Standardoffset of 2 should be adjustable by the user during
receiving.
* 96 Columns with 32 (NTSC) oder 38 (PAL) bytes each.
The columns are build from top down, each byte repesents 2 pixels.
The lower nibble of a byte is the upper pixel and the higer nibble
is the lower pixel. During decoding of a NTSC-picture every 5th pixel
is doubled to result into a correct aspect ratio.
Datablock (old version, must be recognised, but use new version for new software):
* At least 20 bytes, normally 38 bytes $F0 (Datasync)
* 1 byte $00 (Datasync-end)
* 1 byte Datatype (see new version)
* 2 bytes Datalength (High byte first, NOT intel-format)
* n bytes Data
* 2 bytes CRC-sum, high-byte first over all bytes including from datatype
to the last databyte
From including the datatype to the checksum some bytes are converted to
2 bytes, to avoid detecting a false sync.
$00 -> $00 $00
$0F -> $00 $FF
$F0 -> $FF $00
$FF -> $FF $FF
As this conversion is done after building the header, these doublebytes
are counted as one in the field "datalength".
Datablock (new version):
* At least 20 bytes, normally 38 bytes $F0 (Datasync)
* 1 byte $FF (Datasync-end)
* 1 byte Headerlength (in this version 7)
* 1 byte datatype
$00 = Testdata, ignore
$01 = ASCII-Text, end-of-line CR (ASCII 13)
$02 = First sequence of compressed AVIS-Pictures
$03 = Further sequence of compressed AVIS-Pictures
$04 = First sequence of compressed pictures
$05 = Further sequence of compressed pictures
$06 = ADPCM-2/8-Bit-Audio, in the datapart first 2 byte
samplerate in Hz (high-byte first), then datalength-2 byte
sampledata
$07 = Drawing-command
$08 = Control-command
$09 = Audio, datapart looks as this:
1 byte compressiontype
$00 = Audio 8 Bit uncompressed
$01 = ADPCM-1/8-Bit-Audio (own, not used yet)
$02 = ADPCM-2/8-Bit-Audio (soundblaster)
$03 = ADPCM-3/8-Bit-Audio (own)
$04 = ADPCM-4/12-Bit-Audio (dialogic, normally 8kHz)
$05 = Code Excited Linear Prediction (CELP)
$06 = MACE 6 (Apple Computer)
$07 = LPC 10 (Linear Prediction Coding, simple CELP)
$09 = PAC (Ponton Audio Compression)
1 byte Flags
Bit 0: 0=first Block; 1=further Block
Bit 1: 0=further blocks follow; 1=last Block
Bit 2: 0=further Frame; 1=first Frame, ADPCM init
2 byte Samplerate (High-byte first) in Hz
n-4 byte sampledata
* 2 bytes datalength (High byte first, not intel-format)
* 2 bytes two's complement of datalength for security (High byte first)
* n bytes data
* 2 bytes CRC-sum, high-byte first over all bytes from including datatype
to the last databyte
Pictureblocks as well as datablocks of the old type can be interrupted by
a new sync-sequence, the interrupted block is thrown away. All data after
the 96th column or after the CRC-sum are ignored (except syncs, of course)
A pictureblock with less than 90 columns is probably defect and should
not be displayed. Pictureblocks with less than 96 bytes ale filled up to
the end with black pixels.
After a datablock, before switching back to AVIS, you should send about
30 bytes of "trailing trash" to avoid dataerrors in between important data.
Controlcommands
ECHO ON local echo of textlines send as datablocks (standard)
ECHO OFF local echo off.
QVER query version, send your version and profile.
VERSION followed by computer/system and versionnumber,
announcement of the possibilities of the software.
examples:
VERSION PC1.7B11 PC/MS-DOS with version 1.7 beta 11
VERSION MAC1.1.1 Macintosh 1.1.1
VERSION WIN0.1B1 Windows 0.1 beta 1
VERSION AMIGA1.0B Amiga 1.0b
NOSOUND Computer has no possibilities of sound, even if the
softwareversion has (e.g. no soundblaster installed)
NAME Name of the User. e.g.:
NAME Peter Graf
Structure of the AVIS-picture
The videosignal of a connected camera is not digitized in rows, as it is
produced by the camera, but in columns. The AVIS-digitizer produces a
sequence of 96 by 76 (64 at NTSC) pixels with 16 grays. Each byte
transmitted by the digitizer contains two pixels (one per nibble), so
the size of a (PAL-)AVIS-picture is 96*38=3648 bytes. A completely
received AVIS-picture contains 96 columns of 38 (PAL) or 32 (NTSC) bytes.
Since each column is produced during one filed of the camera-videosignal,
the AVIS-pictures have a duration of 1.92 seconds
for PAL or 1.6 seconds for NTSC.
columnpixelformat
picture: 96 columns PAL: NTSC:
0F lu . . . . . . . lu lu 0L 0L
0F lu . . . . . . . lu lu 0H 0H
. . . . . . . . . . . 1L 1L
. . . . . . . . . . . 32 bytes (NTSC) 1H 1H
. . . . . . . . . . . o.38 bytes (PAL) 2L 2L
0F lu . . . . . . . lu lu 2H 2L
0F lu . . . . . . . lu lu 3L 2H
XX lu . . . . . . . lu lu 3H 3L
XX lu lu . . . . . lu lu 4L 3H
4H 4L
lu=lower pixel in high nibble, 5L 4H
upper pixel in low nibble 5H 4H
The Digitizer-Interface
The camerainterface is connected between modem and computer.
It contains 2 switches for the datastream:
- Input : Modem->Computer | Camera->Computer
- Output: Computer->Modem | Camera->Modem
The input-switch has to be switched manually at the interface. It is used
to see your own transmitting picture instead of the incoming from your partner.
The output-switch is controlled by the computer with the DTR-line on the
serial port (Pin 20). Only throught this the computer hat the possibility
to insert datablocks into the AVIS-picture-stream. DTR active means, the
computer sends to the modem.
Handshaking
If the modem uses CTS-handshaking, the computer should use this as well.
If the AVIS-digitizer sends to the modem sets CTS to inactive ("I can not
handle any more data") the computer should rise DTR to active state to stop
AVIS from sending. After the modem is ready again (CTS active) you should
wait for about 5 seconds before you reset DTR again, to let the modem empty
its buffer. If the computer is transmitting anyhow, it should simply hold
the transmitting during CTS is inactive.
RTS-Handshaking to the modem would be possible, but not useful, or, with
the mac, dangerous, because inside the mac the RTS and the DTR signals are
connected and can not be switched seperatly, so the modem would stop
sending data to the computer every time the digitizer sends to the modem.
Sample Pascal sourcecode for AVIS data-stream-analysis
by Christian Wolff, % , "
const
picSync =$0F;
dataSync=$F0;
validsync=20; {SYNCS at least to be a valid sync}
cutoff=10; {max. number of missing columns at end of pict}
xRez=95; {95 columns + 1 sync-column}
yRez=37; {38 rows}
xPix=xRez; {pixelsizes of images}
yPix=yRez*2+1;
picsize=(xrez+1)*(yrez+1); {imagesize in bytes}
picpixel=picsize*2; {imagesize in pixels}
normVertOffs=2; {standard: 2 bytes trash after sync}
type
tPict=array[0..xRez,0..yRez] of byte; {avis-picture}
tData=record
null:byte;
typ:byte;
length:word;
data:array[0..16383] of byte;
end;
var
recPic,actPic,tmpPic:^tPict;
recData,actData,tmpData:^tData;
picSyncCount,picDelay,dataSyncCount,dataCount,verticalOffset,
picX,picY,ntscBorder,stretch:integer;
itsaPic,itsaData,oldheader,doputpic,doshowdata:boolean;
{function to analyse datastream for avis-pictures and avis-datablocks}
{input: pointer to byte to return character, when not in graphics mode}
{output: boolean, true when adat valid character}
{global variables:
graphmode graphics-mode (incoming data plain data or avis-frames)
actPic pointer to return-picture
recPic pointer to recording structure
tmpPic temporary pointer for swapping
doPutPic set, if actPic is valid
actData pointer to return datablock
recData pointer to recording structure
tmpData temporary pointer for swapping
doShowData set, if actData is valid
verticalOffset number of trash-bytes after sync, normally normVertOffs
global variables only used inside the function:
itsAPic receiving picture in progress
itsAData receiving datablock in progress
picX,picY receiving koordinates in picture
stretch variable for expanding NTSC-pixels do PAL-columns
ntscBorder hysterese-variable for detecting PAL/NTSC
dataCount receiving position in datablock
oldheader datablock in old or new format
usecrc set, if the partner uses CRC-sum
crcwrong,crcright counter for automatic switching of usecrc
xx,yy counter}
function getserial(var adat:byte):boolean;
var byt:byte; {incoming byte}
check:word; {checksum}
begin
getserial:=false; {if not otherwise specified, no character returned}
if head1<>tail1 then begin {if character in input-queue then}
byt:=inbuf1^[tail1]; {get character from input-queue to byt}
tail1:=succ(tail1) and bufsize; {adjust input-queue tail-pointer}
if byt=picSync then {is it a picture-sync ($0F)?}
inc(picSyncCount) {yes: count it!}
else begin {otherwise it's end of sync}
if (picSyncCount>validsync) {did we had enough syncs for a valid picture...}
and ((not itsadata) or oldheader) then begin {... and not the new format and we receive a datablock curently}
if not graphmode then {if we are not already in graphics-mode}
inscreen.wipe; {then erase screen}
graphmode:=true; {set graphics-mode on}
if itsapic then begin {do we interrupt a picture?}
if picX>xRez-cutoff then begin {did we had enough columns?}
for yy:=picY to yRez do recPic^[picX,yy]:=0; {fill rest of this column with black}
if picX0 then begin {waiting for the 2 or 3 garbage-bytes before the picture}
dec(picDelay); {decrement counter}
if picDelay=0 then begin {start of picture?}
picX:=0; {reset koordinates}
picY:=0;
itsaData:=false; {it's not a datablock,}
itsaPic:=true; {it's a picture!}
end;
end;
if byt=dataSync then {is it a dataSync ($F0)?}
inc(dataSyncCount) {count it!}
else begin {otherwise it's end of datasync}
if (dataSyncCount>validsync) {did we had enough datasyncs...
and ((not itsadata) or oldheader) then begin {... and not the new format and we receive a datablock curently}
oldheader:=byt=$00; {is it a old-type datablock, interruptable by sync?}
if not graphmode then {if we are not already in graphics-mode}
inscreen.wipe; {then erase screen}
graphmode:=true; {set graphics-mode on}
if itsapic then begin {do we interrupt a picture? return it!}
if picX>xRez-cutoff then begin
for yy:=picY to yRez do recPic^[picX,yy]:=0;
if picX0) then begin {old format, translate}
if byt=$00 then begin {if this is $00}
if evalin=-1 then evalin:=$00 else {no last one: store}
if evalin=$00 then begin evalin:=-1; end else {last one=$00: return $00}
if evalin=$FF then begin byt:=$F0; evalin:=-1; end; {last one=$FF: return $F0}
end else if byt=$FF then begin {if this is $FF}
if evalin=-1 then evalin:=$FF else {no last one: store}
if evalin=$00 then begin byt:=$0F; evalin:=-1; end else {last one=$00: return $0F}
if evalin=$FF then begin evalin:=-1; end; {last one=$FF: return $FF}
end else evalin:=-1; {otherwise reset last one}
end else evalin:=-1;
if evalin<0 then begin {no last one stored?}
if dataCount>0 then begin {drop first byte}
if dataCount>=headerlen then begin {header finished?}
recData^.data[dataCount-headerlen]:=byt; {put byte into structure}
if dataCount-headerlenrecData^.length then begin {else}
itsaData:=false; {datablock finished}
check:=(recData^.data[recData^.length] shl 8) or recData^.data[recData^.length+1]; {read CRC}
if usecrc then begin {do we care for CRC?}
doShowData:=check=incheck; {compare CRC}
if not doShowData then begin {was it wrong?}
inc(crcwrong); {count it}
if crcwrong>10 then usecrc:=false; {beyond treshold? disable CRC}
end else crcwrong:=0; {else reset counter}
end else begin {we do not care}
doshowData:=true; {return datablock}
if check=incheck then {maybe it was ok?}
inc(crcright) {count it}
else crcright:=0; {else reset counter}
if crcright>10 then usecrc:=true; {beyond treshold?, enable CRC}
end;
tmpData:=actData; actData:=recData; recData:=tmpData; {swap pointers (doublebuffering)}
end;
end else begin {header not finished yet}
incheck:=updcrc(byt,incheck); {do crc}
if oldheader then begin {fill old header}
if dataCount=1 then recData^.typ:=byt else
if dataCount=2 then lastbyte:=byt else
if dataCount=3 then recData^.length:=(lastbyte shl 8) or byt;
end else begin {fill new header}
if dataCount=1 then headerlen:=byt else {adjust headersize}
if dataCount=2 then recData^.typ:=byt else
if dataCount=3 then lastbyte:=byt else
if dataCount=4 then recData^.length:=(lastbyte shl 8) or byt else
if dataCount=5 then lastbyte:=byt else
if dataCount=6 then begin
if -recData^.length<>(lastbyte shl 8) or byt then begin
itsadata:=false; {wrong length-check, trash block}
end;
end;
end;
end;
end;
inc(dataCount); {increment position}
end;
end else if itsaPic then begin {do we receive a picture otherwise?}
if stretch<0 then {no stretch, PAL}
recPic^[picX,picY]:=byt {put byte into picture}
else begin {stretch, NTSC, double every 5th pixel}
if stretch=2 then begin
recPic^[picX,picY]:=(byt and $0F) or ((byt and $0F) shl 4);
if picY=yRez then begin {column finished?}
if picX>=xRez then begin {picture finished?}
tmpPic:=actPic; actPic:=recPic; recPic:=tmpPic; {swap pointers}
doputPic:=true; {set flag for returning picture}
itsaPic:=false; {picture finished}
end else begin {not yet, next column}
picY:=0; {to the top}
if stretch>0 then stretch:=0; {if stretch, reset stretch-state}
inc(picX); {increment column}
end;
end else inc(picY); {next pixel}
end else if not graphmode then begin {otherwise, and if no graphics mode}
adat:=byt; {return byte directly}
getserial:=true; {e.g. the answer from the modem}
end;
end;
end;
|
 |