unit Camera;

{Routines used by the Image program for supporting the Data Translation}
{QuickCapture card and the Scion Image Capture 2.}

interface


	uses
		QuickDraw, OSIntf, PickerIntf, PrintTraps, ToolIntf, globals, Utilities, Graphics, File1;


	procedure AverageFrames;
	procedure CaptureAndDisplayQCFrame;
	procedure StartDigitizing;
	procedure StopDigitizing;
	procedure SetVideoChannel;
	procedure MakeMovie;
	function GetQCPixel (h, v: integer): integer;



implementation

	var
		SavePicBaseAddr: ptr;

	procedure CorrectShadingOfLine (PicPtr, BFPtr: ptr; width, BFMean: integer);
{}
{TYPE}
{  lptr=^LineType;}
{VAR}
{  PicLine,BFLine:lptr;}
{  i,value:integer;}
{BEGIN}
{  PicLine:=lptr(PicPtr);}
{  BFLine:=lptr(BFPtr);}
{  FOR i:=0 TO width-1 DO BEGIN}
{    value:=PicLine^[i];}
{    value:=255-value;}
{    value:=(LongInt(value)*BFMean+(BFLine^[i] DIV 2)) DIV BFLine^[i];}
{    IF value>254 THEN value:=254;}
{    IF value<1 THEN value:=1;}
{    PicLine^[i]:=255-value;}
{  END;}
{  }
  {a0=data pointer}
  {a1=blank field data pointer}
  {d0=count}
  {d1=pixel value}
  {d2=blank field pixel value}
  {d3=blank field mean}
  {d4=temp}
  {d5=max pixel value(245)}
  {d6=min pixel value(1)}
	inline
		$4E56, $0000, {   link	a6,#0}
		$48E7, $FEC0, {   movem.l	a0-a1/d0-d6,-(sp)}
		$206E, $000C, {   move.l	12(a6),a0}
		$226E, $0008, {   move.l	8(a6),a1}
		$4280,       {   clr.l	d0}
		$302E, $0006, {   move.w	6(a6),d0}
		$362E, $0004, {   move.w	4(a6),d3}
		$2A3C, $0000, $00FE, {   move.l	#254,d5}
		$2C3C, $0000, $0001, {   move.l	#1,d6}
		$5380,       {   subq.l	#1,d0}
		$4281,       {   clr.l	d1}
		$4282,       {   clr.l	d2}
		$1210,       {L1	move.b	(a0),d1}
		$1419,       {   move.b	(a1)+,d2}
		$4601,       {   not.b	d1}
		$C2C3,       {   mulu.w	d3,d1}
		$2802,       {   move.l	d2,d4}
		$E244,       {   asr.w	#1,d4}
		$D284,       {   add.l	d4,d1}
		$82C2,       {   divu.w	d2,d1}
		$B245,       {   cmp.w	d5,d1}
		$6F02,       {   ble.s	L2}
		$3205,       {   move.w	d5,d1}
		$B246,       {L2	cmp.w	d6,d1}
		$6C02,       {   bge.s	L3}
		$3206,       {   move.w	d6,d1}
		$4601,       {L3	not.b	d1}
		$10C1,       {   move.b	d1,(a0)+}
		$51C8, $FFDE, {   dbra	d0,L1}
		$4CDF, $037F, {   movem.l	(sp)+,a0-a1/d0-d6}
		$4E5E,       {   unlk	a6}
		$DEFC, $000C; {   add.w	#12,sp}
{END;}


	procedure CorrectShading;
		var
			i: integer;
			offset: LongInt;
			p1, p2: ptr;
	begin
		with info^ do begin
				if PicSize <> BlankFieldInfo^.PicSize then begin
						beep;
						exit(CorrectShading);
					end;
				ShowWatch;
				p1 := PicBaseAddr;
				p2 := BlankFieldInfo^.PicBaseAddr;
				for i := 1 to nLines do begin
						CorrectShadingOfLine(p1, p2, PixelsPerLine, BlankFieldMean);
						p1 := ptr(ord4(p1) + info^.BytesPerRow);
						p2 := ptr(ord4(p2) + BlankFieldInfo^.BytesPerRow);
						if i mod 96 = 0 then
							UpdatePicWindow;
					end;
				UpdatePicWindow;
				SetWTitle(wptr, 'Camera(Corrected)');
			end;
	end;


	procedure GetQuickCaptureFrame;
	begin
		if OptionKeyWasDown then begin  {Wait for external trigger, then capture one frame}
				ControlReg^ := BitAnd($82, 255);
				while ControlReg^ < 0 do
					;      {Wait for it to complete}
				StopDigitizing;
			end
		else begin
				ControlReg^ := BitAnd($80, 255); {Start frame capture}
				while ControlReg^ < 0 do
					;      {Wait for it to complete}
			end;
		DTFrameCount := DTFrameCount + 1;
	end;


	procedure CaptureAndDisplayQCFrame;
		var
			tPort: GrafPtr;
	begin
		with info^ do begin
				if (PictureType <> QuickCaptureType) or (PixelsPerLine <> qcWidth) or (nlines <> qcHeight) then
					exit(CaptureAndDisplayQCFrame);
				GetQuickCaptureFrame;
				getPort(tPort);
				SetPort(wptr);
				hlock(handle(qcPort^.portPixMap));
				hlock(handle(CGrafPort(ThePort^).PortPixMap));
				CopyBits(BitMapHandle(qcPort^.portPixMap)^^, BitMapHandle(CGrafPort(ThePort^).PortPixMap)^^, SrcRect, wrect, SrcCopy, nil);
				hunlock(handle(qcPort^.portPixMap));
				hunlock(handle(CGrafPort(ThePort^).PortPixMap));
				SetPort(tPort);
			end;
	end;


	procedure SetReg (index, value: integer);
		const
			RegOffset = $f5fe0;
		var
			reg: ptr;
	begin
		reg := ptr(ScionSlotBase + RegOffset + index * 4);
		reg^ := value;
	end;


	procedure ResetScion (GrabRect: rect; DisplayPoint: point);
		const
			ilutOffset = $f0000;
			LineStartsRamOffset = $f4000;
		type
			LineStartsArray = packed array[0..8191] of UnsignedByte;
			LineStartsType = ^LineStartsArray;
		var
			ScreenRowBytesx2: LongInt;
			LutPtr: ptr;
			LineStarts: LineStartsType;
			EvenStart, OddStart: LongInt;
			width, height, IndexOdd, IndexEven, index, i: integer;
			hstart, vstart: integer;
	begin
		ScreenRowBytesx2 := ScreenRowBytes * 2;
		LoadInputLookupTable(Ptr(ScionSlotBase + ilutOffset));
		with GrabRect, DisplayPoint do begin
				hstart := BitAnd(left, $fffc);
				vstart := BitAnd(top, $fffe);
				width := right - left;
				height := bottom - top;
				EvenStart := LongInt(ScreenBase) + h + ScreenRowBytes * v;
				OddStart := EvenStart + ScreenRowBytes;
				IndexOdd := 0;
				IndexEven := (height div 2) * 16;
			end;
		LineStarts := LineStartsType(ScionSlotBase + LineStartsRamOffset);
		for i := 1 to height div 2 do begin
				LineStarts^[IndexOdd] := BSR(BitAnd(OddStart, $ff000000), 24);
				LineStarts^[IndexOdd + 4] := BSR(BitAnd(OddStart, $ff0000), 16);
				LineStarts^[IndexOdd + 8] := BSR(BitAnd(OddStart, $ff00), 8);
				LineStarts^[IndexOdd + 12] := BitAnd(OddStart, $fc);
				LineStarts^[IndexEven] := BSR(BitAnd(EvenStart, $ff000000), 24);
				LineStarts^[IndexEven + 4] := BSR(BitAnd(EvenStart, $ff0000), 16);
				LineStarts^[IndexEven + 8] := BSR(BitAnd(EvenStart, $ff00), 8);
				LineStarts^[IndexEven + 12] := BitAnd(EvenStart, $fc);
				IndexOdd := IndexOdd + 16;
				IndexEven := IndexEven + 16;
				OddStart := OddStart + ScreenRowBytesx2;
				EvenStart := EvenStart + ScreenRowBytesx2;
			end;
		Index := height * 16;
		LineStarts^[Index] := 0;
		LineStarts^[Index + 4] := 0;
		LineStarts^[Index + 8] := 0;
		LineStarts^[Index + 12] := 1;
		SetReg(1, 0);
		SetReg(2, 162 - (width div 4));
		SetReg(3, 0);
		SetReg(4, 225 - (hstart div 4));
		SetReg(5, 255 - (width div 4));
		SetReg(6, 241 - (vstart div 2));
		SetReg(7, 255 - (height div 2));
	end;


	procedure GetScionFrame (DisplayPoint: point);
  {Captures a single Scion frame to screen memory.}
		type
			IntPtr = ^integer;
		var
			FlagLoc: IntPtr;
			StartTime: LongInt;
	begin
		with DisplayPoint do
			FlagLoc := IntPtr(LongInt(ScreenBase) + h + ScreenRowBytes * v + 4);
		FlagLoc^ := $00ff;
		StartTime := TickCount;
		SetReg(1, BitOr(128, VideoChannel * 4)); {Grab Enable}
		while FlagLoc^ = $00ff do
			if TickCount > (StartTime + 5) then begin
					SetReg(1, 0); {Stop Grabbing}
					exit(GetScionFrame)
				end;
		SetReg(1, 0); {Stop Grabbing}
	end;


	function GetScreenPixel (h, v: integer): integer;
		var
			offset: LongInt;
			p: ptr;
	begin
		offset := LongInt(v) * ScreenRowBytes + h;
		p := ptr(ord4(ScreenBase) + offset);
		GetScreenPixel := BAND(p^, 255);
	end;


	procedure CopyToWindow (src, dst: PixMapHandle; SrcRect, DstRect: rect);
	begin
		hlock(handle(src));
		hlock(handle(dst));
		CopyBits(BitMapHandle(src)^^, BitMapHandle(dst)^^, SrcRect, DstRect, SrcCopy, nil);
		hunlock(handle(src));
		hunlock(handle(dst));
	end;


	procedure CopyScionFrameOffscreen (DisplayPoint: point; wwidth, wheight: integer);
		var
			src, dst: ptr;
			line: integer;
	begin
		with Info^ do begin
				with DisplayPoint do
					src := ptr(LongInt(ScreenBase) + h + ScreenRowBytes * v);
				dst := ptr(LongInt(PicBaseAddr));
				for line := 1 to wheight do begin
						BlockMove(src, dst, wwidth);
						src := ptr(ord4(src) + ScreenRowBytes);
						dst := ptr(ord4(dst) + BytesPerRow);
					end;
			end;
	end;


	procedure DoMiniEventLoop (FullScreenMode: boolean);
		var
			loc: point;
			event: EventRecord;
	begin
		FlushEvents(EveryEvent, 0);
		if not FullScreenMode then
			DrawLabels('X:', 'Y:', 'Value:');
		repeat
			GetMouse(loc);
			LocalToGlobal(loc);
			if not FullScreenMode then
				with loc do
					Show3Values(h, v, GetScreenPixel(h, v));
		until WaitNextEvent(mDownMask + KeyDownMask, Event, 0, nil);
	end;


	procedure CaptureUsingScion;
		var
			GrabRect, ScreenSrcRect: rect;
			DisplayPoint: point;
			FullScreenMode: boolean;
			wwidth, wheight: integer;
			tPort: GrafPtr;
			SaveBackgroundColor, hstart, vstart: integer;
			ignore: integer;
			mloc: point;
			MainDevice: GDHandle;
			SrcPixMap: PixMapHandle;
	begin
		FullScreenMode := OptionKeyDown and (ScreenWidth = 640);
		if FullScreenMode or (ScreenWidth > 640) then begin
				wwidth := MaxScionWidth;
				wheight := 480
			end
		else begin
				wwidth := 552;
				if wwidth > MaxScionWidth then
					wwidth := MaxScionWidth;
				wheight := 436;
			end;
		if ScionInfo <> nil then
			with ScionInfo^.wrect, ScionInfo^ do
				if (wwidth <> right) or (wheight <> bottom) then begin
						changes := false;
						ignore := CloseAWindow(wptr);
					end;
		if (ScionInfo <> nil) and (info^.PictureType <> ScionType) then begin
				SelectWindow(ScionInfo^.wptr);
				info := ScionInfo;
			end;
		if ScionInfo <> nil then
			BringToFront(ScionInfo^.wptr);
		with info^ do
			if PictureType <> ScionType then begin
					if not NewPicWindow('Camera(Scion)', wwidth, wheight) then begin
							beep;
							exit(CaptureUsingScion)
						end;
					ScionInfo := info;
				end;
		KillRoi;
		with info^ do begin
				PictureType := ScionType;
				changes := true;
				SetWTitle(wptr, 'Camera(Live)');
			end;
		hstart := (640 - wwidth) div 2;
		vstart := (480 - wheight) div 2;
		SetRect(GrabRect, hstart, vstart, hstart + wwidth, vstart + wheight);
		if FullScreenMode then
			with DisplayPoint do begin
					h := BitAnd((640 - wwidth) div 2, $fffc);
					v := 0;
				end
		else
			with DisplayPoint do begin
					h := PicLeftBase;
					v := PicTopBase;
				end;
		ResetScion(GrabRect, DisplayPoint);
		if FullScreenMode then begin
				GetPort(tPort);
				SaveBackgroundColor := BackgroundIndex;
				SetBackgroundColor(BlackIndex);
				EraseScreen;
			end;
		if info^.magnification <> 1.0 then
			Unzoom;
		SetReg(1, BitOr(128, VideoChannel * 4)); {Grab Enable}
		DoMiniEventLoop(FullScreenMode);
		SetReg(1, 0);   {Stop Grabbing}
		HideCursor;
		GetScionFrame(DisplayPoint);
		MainDevice := GetMainDevice;
		SrcPixMap := MainDevice^^.gdPMap;
		with DisplayPoint, ScreenSrcRect do begin
				left := h;
				top := v;
				right := left + wwidth;
				bottom := top + wheight;
			end;
		with info^ do
			CopyToWindow(SrcPixMap, osPort^.portPixMap, ScreenSrcRect, PicRect);
		ShowCursor;
		if FullScreenMode then begin
				RestoreScreen;
				SetBackgroundColor(SaveBackgroundColor);
				SetPort(tPort);
			end;
		info^.title := 'Camera';
		ShowMagnification;
		SetWTitle(info^.wptr, 'Camera');
		if (BlankFieldInfo <> nil) and not OptionKeyDown then
			CorrectShading;
		FlushEvents(EveryEvent, 0);
	end;


	procedure StartDigitizing;
		var
			i, width, height: integer;
	begin
		if FrameGrabber = Scion then begin
				CaptureUsingScion;
				exit(StartDigitizing)
			end;
		if Digitizing then begin
				StopDigitizing;
				if BlankFieldInfo <> nil then
					wait(15);
				FlushEvents(EveryEvent, 0); {In case user holds key down too long}
				exit(StartDigitizing)
			end;
		if FrameGrabber = NoFrameGrabber then begin
				PutMessage('Digitizing Requires a Data Translation or SCION frame grabber card.');
				exit(StartDigitizing)
			end;
		if (QuickCaptureInfo <> nil) and (info^.PictureType <> QuickCaptureType) then begin
				SelectWindow(QuickCaptureInfo^.wptr);
				info := QuickCaptureInfo;
			end;
		with info^ do
			if (PictureType <> QuickCaptureType) or (PixelsPerLine <> qcWidth) or (nlines <> qcHeight) then begin
					if not NewPicWindow('Camera', qcWidth, qcHeight) then
						exit(StartDigitizing);
					with info^ do
						if not EqualRect(SrcRect, PicRect) then {Center Frame}
							with SrcRect do begin
									width := right - left;
									height := bottom - top;
									left := (PicRect.right - width) div 2;
									right := left + width;
									top := (PicRect.bottom - height) div 2;
									bottom := top + height;
								end;
				end;
		KillRoi;
		with info^ do begin
				if ScaleToFitWindow then
					ScaleToFit;
				with SrcRect do {Prevents bus errors when Camera window moved.}
					if (top = 0) and (bottom < PicRect.bottom) then begin
							top := top + 1;
							bottom := bottom + 1;
						end;
				ResetQuickCapture;
				Digitizing := true;
				SetItem(VideoMenuH, StartItem, 'Stop Capturing');
				changes := true;
				BinaryPic := false;
				SetWTitle(wptr, 'Camera(Live)');
			end;
		DTFrameCount := 0;
		DTStartTicks := TickCount;
		ContinuousHistogram := false;
	end;


	procedure AddLineToSum (src, dst: ptr; width: LongInt);
{$IFC false}
		type
			SumLineType = array[0..2047] of integer;
			fptr = ^SumLineType;
			lptr = ^LineType;
		var
			FrameLine: lptr;
			SumLine: fptr;
			i: integer;
	begin
		FrameLine := lptr(src);
		SumLine := fptr(dst);
		for i := 0 to width - 1 do
			SumLine^[i] := SumLine^[i] + FrameLine^[i];
	end;
{$ENDC}
inline
{a0=data pointer}
{a1=sum buffer pointer}
{d0=count}
{d1=pixel value}
{d2=temp}
	$4E56, $0000, {link	a6,#0}
	$48E7, $E0C0, {movem.l	a0-a1/d0-d2,-(sp)}
	$206E, $000C, {move.l	12(a6),a0}
	$226E, $0008, {move.l	8(a6),a1}
	$202E, $0004, {move.l	4(a6),d0}
	$5380,              {subq.l	#1,d0}
	$4281,              {clr.l	d1}
	$4282,              {clr.l	d2}
	$1218,              {L1	move.b	(a0)+,d1}
	$3411,              {move.w	(a1),d2}
	$D441,              {add.w  	d1,d2}
	$32C2,              {move.w	d2,(a1)+}
	$51C8, $FFF6, {dbra	d0,L1}
	$4CDF, $0307, {movem.l	(sp)+,a0-a1/d0-d2}
	$4E5E,               {unlk	a6}
	$DEFC, $000C; {add.w	#12,sp}



procedure AverageFrames;
	type
		IntPtr = ^integer;
		SumLineType = array[0..2047] of integer;
		sptr = ^SumLineType;
		lptr = ^LineType;
	var
		AutoSelectAll: boolean;
		SelectionSize, FrameBufferSize, offset, StartTicks: LongInt;
		SumBase, src, srcbase, dst, OffscreenBase: ptr;
		str1, str2: str255;
		xLines, xPixelsPerLine, xPixelsPerLine2, frame, line, pixel: integer;
		aline: LineType;
		GrabRect: rect;
		DisplayPoint: point;
		hstart, vstart, wwidth, wheight, MinV, MaxV, value: integer;
		j, range, FramesAveraged: integer;
		SrcRowBytes, DstRowBytes, i: LongInt;
		SumFrames: boolean;
		iptr: IntPtr;
		FrameLine: lptr;
		SumLine: sptr;
		SaveBlankFieldInfo: InfoPtr;
begin
	SaveBlankFieldInfo := BlankFieldInfo;
	BlankFieldInfo := nil; {We don't want to do shading correction now}
	StopDigitizing;
	BlankFieldInfo := SaveBlankFieldInfo;
	SumFrames := OptionKeyWasDown;
	OptionKeyWasDown := false;
	DrawLabels('Frame:', 'Total:', '');
	if (info <> QuickCaptureInfo) and (info <> ScionInfo) then begin
			PutMessage('You must have an active Camera window(created using Start Digitizing) in order to average frames.');
			exit(AverageFrames)
		end;
	if NotRectangular or NotinBounds then
		exit(AverageFrames);
	ShowWatch;
	AutoSelectAll := not Info^.RoiShowing;
	if AutoSelectAll then
		SelectAll(false);
	with info^.osroiRect do
		SelectionSize := (LongInt(right) - left) * (bottom - top);
	FrameBufferSize := SelectionSize * 2;
	if FrameBufferSize > BigBufSize then begin
			NumToString(FrameBufferSize div 1024, str1);
			NumToString(BigBufSize div 1024, str2);
			str2 := concat(str1, 'K bytes are required, but only ', str2, 'K bytes are available.');
			PutMessage(concat('There is not enough memory to do the requested frame averaging. ', str2));
			if AutoSelectAll or (BlankFieldInfo <> nil) then
				KillRoi
			else
				ShowRoi;
			exit(AverageFrames)
		end;
	WhatToUndo := NothingToUndo;
	WhatsOnClip := Nothing;
	SumBase := BigBuf;
	if FrameGrabber = QuickCapture then begin
			ContinuousHistogram := false;
			ResetQuickCapture
		end
	else begin
			with info^.wrect do begin
					wwidth := right;
					wheight := bottom;
				end;
			hstart := (640 - wwidth) div 2;
			vstart := (480 - wheight) div 2;
			SetRect(GrabRect, hstart, vstart, hstart + wwidth, vstart + wheight);
			with DisplayPoint do begin
					h := PicLeftBase;
					v := PicTopBase;
				end;
			ResetScion(GrabRect, DisplayPoint);
			HideCursor;
		end;
	with info^, info^.osroirect do begin
			offset := left + LongInt(top) * BytesPerRow;
			OffscreenBase := ptr(ord4(PicBaseAddr) + offset);
			if FrameGrabber = QuickCapture then begin
					offset := left + LongInt(top) * qcRowBytes;
					srcbase := ptr(ord4(ptr(DTSlotBase)) + offset);
					SrcRowBytes := qcRowBytes;
				end
			else
				with DisplayPoint do begin
						BringToFront(wptr);
						offset := left + h + (v + top) * ScreenRowBytes;
						srcbase := ptr(ord4(ScreenBase) + offset);
						SrcRowBytes := ScreenRowBytes;
					end;
			xLines := bottom - top;
			xPixelsPerLine := right - left;
			xPixelsPerLine2 := xPixelsPerLine * 2;
		end;
	dst := SumBase;
	for line := 1 to xLines do begin {zero buffer}
			BlockMove(@BlankLine, dst, xPixelsPerLine2);
			dst := ptr(ord4(dst) + xPixelsPerLine2);
		end;
	info^.title := 'Camera';
	ShowMagnification;
	StartTicks := TickCount;
	for frame := 0 to FramesToAverage - 1 do begin
			Show2Values(frame + 1, FramesToAverage);
			if FrameGrabber = QuickCapture then
				GetQuickCaptureFrame
			else
				GetScionFrame(DisplayPoint);
			src := srcbase;
			dst := SumBase;
			for line := 1 to xLines do begin
					AddLineToSum(src, dst, xPixelsPerLine);
					src := ptr(ord4(src) + SrcRowBytes);
					dst := ptr(ord4(dst) + xPixelsPerLine2);
				end;
			if FrameGrabber = QuickCapture then
				UpdateScreen(info^.roiRect);
			if CommandPeriod then begin
					beep;
					if AutoSelectAll then
						KillRoi
					else
						ShowRoi;
					exit(AverageFrames);
				end;
		end; {for}
	src := SumBase;
	dst := OffscreenBase;
	DstRowBytes := info^.BytesPerRow;
	if SumFrames then begin
			MinV := 32767;
			MaxV := 0;
			iptr := IntPtr(src);
			for i := 1 to SelectionSize do begin
					value := iptr^;
					if value > MaxV then
						MaxV := value;
					if value < MinV then
						MinV := value;
					iptr := IntPtr(ord4(iptr) + 2);
				end;
			range := MaxV - MinV;
			if range <> 0 then
				for line := 1 to xLines do begin
						SumLine := sptr(src);
						FrameLine := lptr(dst);
						for j := 0 to xPixelsPerLine - 1 do begin
								value := SumLine^[j] - MinV + 1;
								value := LongInt(value) * 254 div range;
								FrameLine^[j] := value;
							end;
						src := ptr(ord4(src) + xPixelsPerLine2);
						dst := ptr(ord4(dst) + DstRowBytes);
					end
			else
				beep;
		end
	else
		for line := 1 to xLines do begin
				SumLine := sptr(src);
				FrameLine := lptr(dst);
				for j := 0 to xPixelsPerLine - 1 do
					FrameLine^[j] := SumLine^[j] div FramesToAverage;
				src := ptr(ord4(src) + xPixelsPerLine2);
				dst := ptr(ord4(dst) + DstRowBytes);
			end;
	RealToString((TickCount - StartTicks) / 60.0, 1, 2, str1);
	ShowFrameRate(concat(Long2str(FramesToAverage), ' frames', cr, str1, ' seconds', cr), StartTicks, FramesToAverage);
	UpdatePicWindow;
	if AutoSelectAll then
		KillRoi
	else
		ShowRoi;
	if BlankFieldInfo <> nil then
		CorrectShading;
end;


procedure StopDigitizing;
begin
	if digitizing then
		with info^ do begin
				ShowFrameRate('', DTStartTicks, DTFrameCount);
				CopyToWindow(qcPort^.portPixMap, osPort^.portPixMap, PicRect, PicRect);
				SetItem(VideoMenuH, StartItem, 'Start Capturing');
				Digitizing := false;
				ContinuousHistogram := false;
				with info^ do
					if PictureType = QuickCaptureType then begin
							title := 'Camera';
							ShowMagnification;
						end;
				if (BlankFieldInfo <> nil) and not OptionKeyDown then
					CorrectShading;
			end;
end;


procedure SetVideoChannel;
	var
		TempChannel: integer;
begin
	if FrameGrabber = Scion then begin
			TempChannel := GetInt('Scion Input Channel(1..4):', VideoChannel + 1);
			TempChannel := TempChannel - 1;
		end
	else
		TempChannel := GetInt('QuickCapture Input Channel(0..3):', VideoChannel);
	if (TempChannel >= 0) and (TempChannel <= 3) then
		VideoChannel := TempChannel;
end;


procedure MakeMovie;
	var
		nFrames, wleft, wtop, width, height, frame, i, LastFrame: integer;
		FramesWanted: integer;
		OutOfMemory: boolean;
		name, str1, str2: str255;
		FrameInfo: array[1..MaxPics] of InfoPtr;
		DisplayPoint: point;
		StartTicks, NextTicks, interval, ElapsedTime: LongInt;
		SecondsBetweenFrames, seconds: extended;
		frect: rect;
		MainDevice: GDHandle;
		SourcePixMap: PixMapHandle;
		TimeStamp: array[1..MaxPics] of LongInt;
begin
	with info^ do begin
			if (PictureType <> QuickCaptureType) and (PictureType <> ScionType) then begin
					PutMessage('You must be digitizing in order to make a movie.');
					exit(MakeMovie);
				end;
			StopDigitizing;
			FramesWanted := GetInt('Number of Frames:', 10);
			if FramesWanted = -MaxInt then
				exit(MakeMovie);
			if FramesWanted < 1 then
				FramesWanted := 1;
			if FramesWanted > MaxPics then
				FramesWanted := MaxPics;
			if RoiShowing then
				with osRoiRect do begin
						wleft := left;
						wtop := top;
						width := right - left;
						height := bottom - top;
					end
			else
				with PicRect do begin
						wleft := 0;
						wtop := 0;
						width := right - left;
						height := bottom - top;
					end;
		end; {with}
	if FrameGrabber = Scion then begin
			with DisplayPoint do begin
					h := PicLeftBase;
					v := PicTopBase;
				end;
			with frect do begin
					left := PicLeftBase + wleft;
					top := PicTopBase + wtop;
					right := left + width;
					bottom := top + height;
				end;
		end
	else
		with frect do begin
				left := wleft;
				top := wtop;
				right := left + width;
				bottom := top + height;
			end;
	nFrames := 0;
	repeat
		NumToString(nFrames, name);
		OutOfMemory := not NewPicWindow(name, width, height);
		if not OutOfMemory then begin
				nFrames := nFrames + 1;
				FrameInfo[nFrames] := info;
			end;
	until (nFrames = FramesWanted) or OutOfMemory;
	SecondsBetweenFrames := GetReal('Delay Between Frames(seconds):', 0.0);
	DrawLabels('Frame:', 'Total:', '');
	if SecondsBetweenFrames = BadReal then
		Exit(MakeMovie);
	if SecondsBetweenFrames < 0.0 then
		SecondsBetweenFrames := 0.0;
	interval := round(60.0 * SecondsBetweenFrames);
	if FrameGrabber = Scion then begin
			HideCursor;
			MainDevice := GetMainDevice;
			SourcePixMap := MainDevice^^.gdPMap;
		end
	else begin
			ShowWatch;
			SourcePixMap := qcPort^.portPixMap;
			ResetQuickCapture;
		end;
	StartTicks := TickCount;
	NextTicks := StartTicks;
	LastFrame := nFrames;
	for frame := 1 to nFrames do begin
			NextTicks := NextTicks + Interval;
			TimeStamp[frame] := TickCount;
			with FrameInfo[frame]^ do begin
					if FrameGrabber = QuickCapture then
						GetQuickCaptureFrame
					else
						GetScionFrame(DisplayPoint);
					CopyToWindow(SourcePixMap, osPort^.portPixMap, frect, SrcRect);
					changes := true;
				end;
			if Interval > 0 then begin
					Show2Values(frame, nFrames);
					while TickCount < NextTicks do begin
							if CommandPeriod then begin
									beep;
									LastFrame := frame;
									exit(MakeMovie);
								end;
						end;
				end;
		end; {for}
	seconds := (TickCount - StartTicks) / 60.0;
	RealToString(seconds, 1, 2, str1);
	str1 := concat(long2str(nFrames), ' frames', cr, str1, ' seconds', cr);
	if nFrames >= seconds then
		ShowFrameRate(str1, StartTicks, nFrames)
	else begin
			RealToString(seconds / nFrames, 1, 2, str2);
			ShowMessage(concat(str1, str2, ' seconds/frame'));
		end;
	for frame := 1 to LastFrame do begin
			ElapsedTime := TimeStamp[frame] - StartTicks;
			if interval < 60 then
				RealToString(ElapsedTime, 6, 0, name)
			else
				RealToString(ElapsedTime / 60.0, 9, 2, name);
			i := 1;
			while (name[i] = ' ') and (i <= 6) do begin
					name[i] := '0';
					i := i + 1;
				end;
			SetWTitle(FrameInfo[frame]^.wptr, name);
			with FrameInfo[frame]^ do begin
					title := name;
					UpdateWindowsMenuItem(PicSize, title, PicNum);
				end;
		end;
end;


function GetQCPixel (h, v: integer): integer;
	var
		offset: LongInt;
		p: ptr;
begin
	with Info^ do begin
			if (h < 0) or (v < 0) or (h >= qcWidth) or (v >= qcHeight) then begin
					GetQCPixel := WhiteIndex;
					exit(GetQCPixel);
				end;
			offset := LongInt(v) * qcRowBytes + h;
			if offset >= LongInt(qcHeight) * qcRowBytes then begin
					GetQCPixel := WhiteIndex;
					exit(GetQCPixel);
				end;
			p := ptr(ord4(ptr(DTSlotBase)) + offset);
			GetQCPixel := BAND(p^, 255);
		end;
end;



end.