[squeak-dev] The Trunk: MorphicExtras-eem.293.mcz

commits at source.squeak.org commits at source.squeak.org
Sat Apr 17 02:14:18 UTC 2021


Eliot Miranda uploaded a new version of MorphicExtras to project The Trunk:
http://source.squeak.org/trunk/MorphicExtras-eem.293.mcz

==================== Summary ====================

Name: MorphicExtras-eem.293
Author: eem
Time: 16 April 2021, 7:14:15.621938 pm
UUID: 27489c5b-4cc5-4581-905d-881e877c32d6
Ancestors: MorphicExtras-mt.292

Add frame buffering to the CameraInterface (i.e. if possible the CameraPlugin copies data directly into a pinned bitmap instead of into an internal buffer which is then copied into the bitmap in getFrameForCamera:into:.  Update the camera:framesDo:while: utility to use buffering and/or interrupt notification if possible.

=============== Diff against MorphicExtras-mt.292 ===============

Item was added:
+ ----- Method: CameraInterface class>>bufferedInterruptDrivenVideoTest: (in category 'test') -----
+ bufferedInterruptDrivenVideoTest: camNum
+ 	"A quick test of video input. Displays video on the screen until the mouse is pressed.
+ 	 Answer nil if the interrupt-driven interface is unavailable."
+ 	"self bufferedInterruptDrivenVideoTest: 1"
+ 	"self bufferedInterruptDrivenVideoTest: 2"
+ 	"[self bufferedInterruptDrivenVideoTest: 2] fork.
+ 	  self bufferedInterruptDrivenVideoTest: 1"
+ 
+ 	| semaphore height frameExtent frameBuffer |
+ 	height := 16.
+ 	1 to: camNum - 1 do:
+ 		[:camIndex| "N.B. the extent of an unopened camera is 0 at 0"
+ 		height := height + (self frameExtent: camIndex) y + 16].
+ 	(self cameraIsOpen: camNum) ifFalse:
+ 		[(self openCamera: camNum width: 352 height: 288) ifNil:
+ 			[self inform: 'no camera'.
+ 			 ^nil]].
+ 	frameExtent := self frameExtent: camNum.
+ 	frameBuffer := Form extent: frameExtent depth: 32.
+ 	frameBuffer bits pin.
+ 	self camera: camNum setFrameBuffer: frameBuffer bits.
+ 		 
+ 	semaphore := Semaphore new.
+ 	[self camera: camNum setSemaphore: (Smalltalk registerExternalObject: semaphore)]
+ 		on: Error
+ 		do: [:err|
+ 			Smalltalk unregisterExternalObject: semaphore.
+ 			self inform: 'interrupt-driven camera interface unavailable: ', err messageText.
+ 			^nil].
+ 	[| n startTime frameCount msecs fps |
+ 	 [semaphore wait.
+ 	  startTime ifNil:
+ 		[frameCount := 0.
+ 		 frameExtent := self frameExtent: camNum.
+ 		"N.B. the actual frame size may not be determined until delivery of the first frame.
+ 		 So resize the form if necessary."
+ 		 frameExtent ~= frameBuffer extent ifTrue:
+ 			[frameBuffer := Form extent: frameExtent depth: 32 bits: frameBuffer bits].
+ 		 startTime := Time millisecondClockValue].
+ 	  Sensor anyButtonPressed] whileFalse:
+ 		[n := self getFrameForCamera: camNum into: frameBuffer bits.
+ 		n > 0 ifTrue:
+ 			[frameCount := frameCount + 1.
+ 			 frameBuffer displayAt: 16 @ height]].
+ 	 msecs := Time millisecondClockValue - startTime.
+ 	 fps := (frameCount * 1000) // msecs.
+ 	 ^(self cameraName: camNum), ': ', frameExtent printString, ' ', frameCount printString, ' frames at ', fps printString, ' frames/sec']
+ 		ensure:
+ 			[self closeCamera: camNum.
+ 			 Smalltalk unregisterExternalObject: semaphore.
+ 			 Sensor waitNoButton]!

Item was changed:
  ----- Method: CameraInterface class>>camera:framesDo:while: (in category 'utilities') -----
  camera: cameraNum framesDo: aBlock while: whileBlock
+ 	"Evaluate aBlock every time a frame becomes available.  Answer a tuple of frames per second
+ 	 and the number of 16ms delays per second if polling is used, plus indications of which schemes
+ 	 were used. Be destructive; use only one bitmap, overwriting its contents with each successive frame.
+ 	 Use the buffered interface if possible. It is the sender's responsibility to open and close the camera."
+ 	| form bitmap schemes delay start duration frameCount delayCount semaphore  |
- 	"Evaluate aBlock every time a frame becomes available.  Answer a tuple of frames per second and number of 16ms delays per second.
- 	 Be destructive; use only one bitmap, overwriting its contents with each successive frame.
- 	 It is the sender's responsibility to open and close the camera."
- 	| form bitmap delay start duration frameCount delayCount |
  	form := Form
  				extent: (self frameExtent: cameraNum)
  				depth: 32.
  	bitmap := form bits.
+ 	bitmap pin.
+ 	schemes := Array new writeStream.
+ 	[self camera: cameraNum setFrameBuffer: bitmap.
+ 	 schemes nextPut: 'buffered']
+ 		on: Error
+ 		do: [:err|
+ 			bitmap unpin.
+ 			schemes nextPut: 'copied'].
+ 	semaphore := Semaphore new.
+ 	[self camera: cameraNum setSemaphore: (Smalltalk registerExternalObject: semaphore).
+ 	 schemes nextPut: 'interrupt driven']
+ 		on: Error
+ 		do: [:err|
+ 			Smalltalk unregisterExternalObject: semaphore.
+ 			semaphore := nil.
+ 			schemes nextPut: 'polling'].
  	delay := Delay forMilliseconds: (1000 / 60) asInteger. "60 fps is fast"
+ 
  	start := Time utcMicrosecondClock.
  	frameCount := delayCount := 0.
+ 	[semaphore ifNotNil:
+ 		[semaphore wait].
+ 	[(self getFrameForCamera: cameraNum into: bitmap) <= 0] whileTrue:
- 	[[(self camera: cameraNum getParam: 1) <= 0] whileTrue:
  		[delay wait. delayCount := delayCount + 1].
- 	 self getFrameForCamera: cameraNum into: bitmap.
  	 frameCount := frameCount + 1.
  	 aBlock value: form.
  	 whileBlock value] whileTrue.
  	^{ frameCount * 1.0e6 / (duration := Time utcMicrosecondClock - start).
+ 		delayCount * 1.0e6 / duration },
+ 	 schemes contents
- 		delayCount * 1.0e6 / duration }
  
  	"| cameraNum |
  	 self openCamera: (cameraNum := 1) width: 640 height: 480.
  	 self waitForCameraStart: cameraNum.
  	 [self camera: cameraNum framesDo: [:bitmap| bitmap display] while: [Sensor noButtonPressed]] ensure:
  		[self closeCamera: cameraNum]"!

Item was added:
+ ----- Method: CameraInterface class>>camera:setFrameBuffer: (in category 'camera ops') -----
+ camera: cameraNum setFrameBuffer: frameBuffer
+ 	"Set a pinned non-pointer object as the frame buffer for the camera.
+ 	 Fail if cameraNum does not reference an open camera, or if the buffer is not large enough."
+ 	<primitive: 'primSetCameraBuffers' module: 'CameraPlugin' error: ec>
+ 	^self primitiveFailed!

Item was added:
+ ----- Method: CameraInterface class>>camera:setFrameBufferA:B: (in category 'camera ops') -----
+ camera: cameraNum setFrameBufferA: frameBufferA B: frameBufferBOrNil
+ 	"Set a pair of pinned non-pointer objects as the frame buffers for the camera.
+ 	 If both are non-nil the plugin will fill them alternating between first frameBufferA and second frameBufferBOrNil.
+ 	 Fail if frameBufferBOrNil is not nil and a different size from frameBufferA.
+ 	 Fail if cameraNum does not reference an open camera, or if the buffers are not large enough."
+ 	<primitive: 'primSetCameraBuffers' module: 'CameraPlugin' error: ec>
+ 	^self primitiveFailed!

Item was changed:
  ----- Method: CameraInterface class>>interruptDrivenVideoTest: (in category 'test') -----
  interruptDrivenVideoTest: camNum
  	"A quick test of video input. Displays video on the screen until the mouse is pressed.
  	 Answer nil if the interrupt-driven interface is unavailable."
  	"self interruptDrivenVideoTest: 1"
  	"self interruptDrivenVideoTest: 2"
  	"[self interruptDrivenVideoTest: 2] fork.
  	  self interruptDrivenVideoTest: 1"
  
  	| semaphore height frameExtent |
  	height := 16.
  	1 to: camNum - 1 do:
+ 		[:camIndex| "N.B. the extent of an unopened camera is 0 at 0"
- 		[:camIndex| "N.B. the of an unopened camera is 0 at 0"
  		height := height + (self frameExtent: camIndex) y + 16].
  	(self cameraIsOpen: camNum) ifFalse:
  		[(self openCamera: camNum width: 352 height: 288) ifNil:
  			[self inform: 'no camera'.
  			 ^nil]].
  	semaphore := Semaphore new.
  	[self camera: camNum setSemaphore: (Smalltalk registerExternalObject: semaphore)]
  		on: Error
  		do: [:err|
  			Smalltalk unregisterExternalObject: semaphore.
  			self inform: 'interrupt-driven camera interface unavailable: ', err messageText.
  			^nil].
  	[| f n startTime frameCount msecs fps |
  	 [semaphore wait.
  	 "N.B. the frame extent may not be known until the delivery of the first frame.
  	  So we have to delay initialization."
  	  startTime ifNil:
  		[(frameExtent := self frameExtent: camNum) x = 0 ifTrue: [self inform: 'no camera'. ^nil].
  		 f := Form extent: (self frameExtent: camNum) depth: 32.
  		 frameCount := 0.
  		 startTime := Time millisecondClockValue].
  	  Sensor anyButtonPressed] whileFalse:
  		[n := self getFrameForCamera: camNum into: f bits.
  		n > 0 ifTrue:
  			[frameCount := frameCount + 1.
  			 f displayAt: 16 @ height]].
  	 msecs := Time millisecondClockValue - startTime.
  	 fps := (frameCount * 1000) // msecs.
  	 ^(self cameraName: camNum), ': ', frameExtent printString, ' ', frameCount printString, ' frames at ', fps printString, ' frames/sec']
  		ensure:
  			[self closeCamera: camNum.
  			 Smalltalk unregisterExternalObject: semaphore.
  			 Sensor waitNoButton]!

Item was changed:
  ----- Method: CameraInterface class>>videoTest: (in category 'test') -----
  videoTest: camNum
  	"A quick test of video input. Displays video on the screen until the mouse is pressed."
  	"self videoTest: 1"
  	"self videoTest: 2"
  
  	| frameExtent f n startTime frameCount msecs fps |
+ 	(self cameraIsOpen: camNum) ifFalse:
+ 		[(self openCamera: camNum width: 320 height: 240) ifNil:
+ 			[self inform: 'no camera'.
+ 			 ^nil]].
- 	(self openCamera: camNum width: 320 height: 240) ifNil: [^ self inform: 'no camera'].
  	self waitForCameraStart: camNum.
  	(frameExtent := self frameExtent: camNum) x = 0 ifTrue: [^ self inform: 'no camera'].
  	f := Form extent: (self frameExtent: camNum) depth: 32.
  	frameCount := 0.
  	startTime := nil.
  	[Sensor anyButtonPressed] whileFalse:
  		[n := self getFrameForCamera: camNum into: f bits.
  		n > 0 ifTrue:
  			[startTime ifNil: [startTime := Time millisecondClockValue].
  			frameCount := frameCount + 1.
  			f display]].
  	Sensor waitNoButton.
  	msecs := Time millisecondClockValue - startTime.
  	self closeCamera: camNum.
  	fps := frameCount * 1000 // msecs.
+ 	^(self cameraName: camNum), ': ', frameExtent printString, ' ', frameCount printString, ' frames at ', fps printString, ' frames/sec'!
- 	^frameExtent printString, ' ', frameCount printString, ' frames at ', fps printString, ' frames/sec'!



More information about the Squeak-dev mailing list