[comp.windows.news] NeWS port with integrated Video

greg@parallax.UUCP (Greg Cockroft) (12/18/87)

	I have been asked to post a description to NeWS-makers of the pNeWS
	demonstration which was given at the NeWS SIG at the recent SUG.
	The demo was of a NeWS port with integrated NTSC video.

	The software requires a Parallax 1280 board set. The current version of
	the board set is 4 VME slots. The demonstration at the SIG used a Sun
	3/160.  AT and QBUS version of the 1280 are also available. pNeWS 
	currently only exists on a Sun workstation.  It could easily be ported
	to a number of other hardware platforms, leveraging off from the 
	portability of NeWS.  The board set contains a 2kx2kx8 bit framebuffer,
	customized graphics processor, video hardware etc..
	A high level command set is used to draw graphics on the display. 
	Rectangle clipping lists, polygons, polylines, etc..

	Mail technical questions to me.
    Product and pricing information can be received by calling Parallax
	at 408-727-2220. Ask for a salesman.

	I have been pushing for discount hardware and free software for
	universities.

			-greg.
	




							pNeWS  Manual
							Greg Cockroft
					Sat Nov  7 20:23:39 EST 1987

pNeWS is an implementation of Sun's NeWS windowing system written for Parallax
Graphics graphics processors.  This document assumes a working knowledge of
the Sun NeWS manual. 

In addition to the strong graphics capabilities provided in NeWS via PostScript,
pNeWS provides extensions for adding video capability.  These extensions are,
live video, still video frame grabbing, and graphics over video.
The goal was to add as few new operators as possible.

GENERAL

In order to support live video, Parallax graphics boards store display data
in two different formats in display memory.  A separate bitplane is used to
tell video output circuitry which areas of the display are video.  These
video areas must be on modulus 16 X boundaries.  Video areas are represented 
in pNeWS by a adding an attribute to the Canvas Dictionary.  This attribute is
called Video.  It is a boolean and can be read as well as set.  See the NeWS
manual chapter 11 (PostScript Type Extensions).

The programmer will probably never need to set this flag.  A new class has
been defined called VideoWindow.  VideoWindow is a subclass of the 
DefaultWindow class.  It enforces the modulus 16 X boundary condition and
maps a Video-type Canvas.  Source for the VideoWindow class can be found in
Appendix A.

If graphics windows on top of video windows are not aligned properly, 
blotches will occur at the junction.  Therefore, it is more desirable
when all windows are aligned.  This can be accomplished by changing two
methods in the DefaultWindow class.  The changed methods are in
Appendix B.

A Video canvas containing live video will obtain damage differently than 
a normal NeWS canvas.  Damage will be received any time the live video
canvas is moved, obscured, or unobscured.  Because of the large offscreen 
memory size available, several video canvases can be retained without using
any host memory.  The amount of offscreen memory available for canvas cacheing
is determined at startup time.  



Syntax for new operators.

PARALLAX      (string) readnum  parallax - (string)

This general purpose command will write a stream of commands to the 1280
board set.  The requested number of bytes in readnum will be read and placed
in the result string. ** This is a use at your own risk command **   
It can place pNeWS in a totally inoperable state. This command was created to
give users full access to the command set on the board, without cluttering
up NeWS with parallax specific operators.

VSTART			priority x y vstart -

Fill current PostScript path with live video. 

Priority is an integer in the range of 0-3. 
Live video at 30 frames a second uses all of the board's resources. 
Some frames occassionally need to be dropped to draw complex graphics.
The highest priority video can be set at is 0.  Its' use is not suggested.
Try 2. x & y are integers which determine the lower left offset within
the NTSC video frame. (0,0) works just fine.  Only one video path can
be active at a time. 


VSTOP		     - vstop -

Stops the current live video path.  If no video paths are active,
nothing happens.

VSOURCE		     channel vsource -

Selects the video channel all video operations will occur from.
Channel must be either 0 or 1.  The video source is part of the
graphics context, and will be 0 after initgraphics.

VZOOMON          canvas canvas vzoomon -

This command affects the video ouput circuitry.  It is usefull for zooming
a live video window to cover a full 1280x1024 display.
If the first canvas is null, the non null canvas will be zoomed an integer 
number of times to a maximum of the root canvas size.  The aspect ratio 
will be maintained. 
If the first canvas is not null, the display will remain at a 1 to 1 zoom up
to the top of the first canvas, and the second canvas will be zoomed to fill
the remainder of the root canvas size.

VZOOMON          - vzoomoff -

Turns off the current zoom.

READCANVAS    string  readcanvas  canvas

This has exactly the same syntax and limitations as the readcanvas operator 
defined in Chapter 12 of the NeWS manual (PostScript Operator Extensions).

If string is  (VideoFrame) the resulting canvas will be a full NTSC video
frame.  Width 640, height 480, and depth 8.  It will be in YUV format.

If string is  (VideoField) the resulting canvas will be a NTSC video
field.  Width 640, height 240, and depth 8.  It will be in YUV format.

If string is  (VideoGreyFrame) the resulting canvas will be a greyscale
canvas in graphics format.  Width 640, height 480, and depth 8. 

If string is  (VideoGreyField) the resulting canvas will be a greyscale
canvas in graphics format.  Width 640, height 240, and depth 8. 

Note: readcanvas when used with the special video filenames, will always
	return the same canvas.  If multiple canvases need to be read, before
	display on the screen, they should be imaged to an intermediate unmapped
	canvas.	 The first time this operator is used a 640x482 area of offscreen
	memory is obtained.  If no offscreen memory is available, a VM error
	will be generated.  The offscreen area will be locked for further uses
	of readcanvas.  If you require this operator and also use alot of
	retained canvasses, you should put something like
		(VideoFrame) readcanvas pop
	in your user.ps
	

IMAGECANVAS

Imagecanvas has exactly the same syntax, but if the source and destination
are in display memory, hardware will be used for squeeze/expand. 
The ratio of the destination size to source size has a granularity of
n/256 for the hardware operation.  In the future, the use of the hardware
will be affected the linequality flag in the graphics context.

Imaging a YUV canvas to an graphics canvas will cause the YUV pixels to be
converted into 24 bit pixels.  If the display device is 8 bits, the pixels
will then be dithered to 8 bit color.

Imaging a graphics canvas onto a YUV canvas is not yet supported.


CODE FRAGMENTS

To use video capabilities we first need to create a video window. 
This is accomplished by calling the /new method of the VideoWindow 
class.

	framebuffer /new VideoWindow send

This has created an instance of the VideoWindow class and left it on 
the stack.  The parent window is the display.  We will always need to 
refer to our window later so we should have done this.

	/win framebuffer /new VideoWindow send def

We can now refer to our window by the name win.
Getting our video window displayed on the screen is no different than 
any other window.

	/reshapefromuser win send

Will allow the user to pick the placement and size of the window.

	/map win send

Will cause the window to be displayed on the screen.


Ok we've got a video window on the screen.  To display video in the window
we need to write a PaintClient PostScript procedure.  This procedure will
be executed any time the window is damaged.  Mapping a window, the last
step we executed above causes a window to be damaged.  To have a video window
which simply displays live video the following will work.

	/PaintClient {
		gsave				% Save graphics state
		newpath clipcanvas  % Reset the canvas clip
		initclip clippath   % Set current path to inside of window
		vstop 			    % Stop previous live video
		2 0 0 vstart        % Start video
		grestore			% Restore graphics state
		} def

To really make this example run, we would have needed to pass the PaintClient
procedure to our window before we mapped it.  We did things in a different 
order to make it less confusing.  Here is the complete example of a 
client which displays a live video window.     

	/win framebuffer /new VideoWindow send def
	{
		/PaintClient {
			gsave				% Save graphics state
			newpath clipcanvas  % Reset the canvas clip
			initclip clippath   % Set current path to inside of window
			vstop 			    % Stop previous live video
			2 0 0 vstart        % Start video
			grestore			% Restore graphics state
			} def
	} win send

	/reshapefromuser win send
	/map win send


Now that the basics are covered, the rest of the examples will just show
the required PaintClient procedure.  Let's try filling a window with a
frame of still video.

	/PaintClient {
		gsave				% Save graphics state
		newpath clipcanvas  % Reset the canvas clip
	    640 480 scale		% original size of frame 
	    (VideoFrame) readcanvas 
		imagecanvas 
		grestore			% Restore graphics state
	} def

In the example above we always reset the canvas clip.  This means the
entire window contents will always be redrawn regardless of the damage
that occurrs to the window.  The reason for this is that if the current
source of video is constantly changing we always want the same frame 
displayed.  Otherwise if part of a window was covered and then uncovered
the uncovered part would be drawn with a new frame.

If we want to fill a window with a video frame, regardless of the window
size, we will need to scale proportional to the window size.

	/PaintClient {
		gsave				% Save graphics state
		newpath clipcanvas  % Reset the canvas clip
		initclip clippath   % Set current path to inside of window
		pathbbox scale      % Scale to fit window
		pop pop				% pathbbox gave us 2 extra numbers
	    (VideoFrame) readcanvas 
		imagecanvas 
		grestore			% Restore graphics state


IMPLEMENTATION LIMITATIONS and DETAILS

These limitations are specific to the 1280 series 8 bitplane
graphics processor.

Only 32 colors are available for graphics over video.  Of these 
32 colors 8 are greyscale colors.  This is transparent to the 
programmer.  24 bit true color values are mapped as best as possible 
to the available 32 colors.

Graphics over live video has no fixed color.  The color will fluctuate
between the 32 graphics over video color values, based on the brightness
of the video underneath.  An implementation could be developed which 
would allow one fixed color of graphics over video. The tradeoff would
be that only one color could be used for graphics over still video, and
32 color entries would be lost for plain graphics.

There are limitations to the path that live video can be clipped.
Live video cannot be stopped and then restarted on a horizontal 
scanline.  No errors will be generated, the area to the right will just
be cleared.  Live video can be clipped to a maximum of 16 rectangles.
If the requested video path is curved or a round window is placed
on top of the live video window, a fit of 16 rectangles is applied
to the interior of the path.



							APPENDIX A
						VideoWindow Class
%
%  Video Window class
% 

/VideoWindow DefaultWindow
dictbegin
dictend
classbegin

%
% methods
%
/new {  % parentcanvas -> window
	/new super send begin 
	currentdict
	end
	} def

%/totop {GetCanvas canvastotop ClientCanvas canvastotop } def% - => -  (Puts window/icon on top)
%/tobottom {GetCanvas canvastobottom ClientCanvas canvastobottom } def % - => - (" " bottom)

/map {
	/map super send
	/FrameCanvas load /Video true put  	   % make video
	/ClientCanvas load /Video true put  	   % make video
	/IconCanvas load /Video true put  	   % make video
	%/ClientCanvas load /Transparent false put  % video canvas must 
											   % be opaq.
	} def

/move { % x y => -  (Moves window/icon to x y.  Does not change mapping)
	exch -16 and  		% align
	exch
	/move super send
	} def

/reshape { % x y w h => -  (Re-shapes window from BBox)
	exch 15 add -16 and   % x y h w
	exch 4 -1 roll		  % y w h x
	-16 and 4 1 roll      % x y w h
	/reshape super send
	} def

classend def



							APPENDIX B
					Modifications to DefaultWindow

    /reshape { % x y w h => -  (Re-shapes window from BBox)
						  % align for video
	exch 15 add -16 and   % x y h w
	exch 4 -1 roll		  % y w h x
	-16 and 4 1 roll      % x y w h

		The rest is the same
	



    /move { % x y => -  (Moves window/icon to x y.  Does not change mapping)
		exch -16 and  % align for video
		exch

		The rest is the same