[visionegg] Re: Displaying raw movies
- From: Martin Spacek <mspacek@xxxxxxxxxxxxxxx>
- To: visionegg@xxxxxxxxxxxxx
- Date: Wed, 22 Sep 2004 21:44:33 -0700
Hi Andrew,
Thanks, that worked like a charm! With Numeric, it takes about 30sec to
load a 120 MB file into a 3D array. With numarray, it takes only a
couple of seconds to do the same. Both seem to be equally quick in
accessing the contents after the fact though (is this because you've
converted the numarray into a Numeric array, as mentioned in the
comments?). On our setup (512MB RAM, Athlon 700MHz, Radeon 9800 Pro,
Windows 2000) it takes about 0.8 ms to load a 2D frame from the 3D
array, draw it, swap the buffers, and change the bit value on our
digital out card (viewed on an oscilloscope). This is plenty fast enough
for the 5 ms available on a 200Hz display. Unfortunately, if I create
two separate texture stimuli to run two movies simultaneously within the
same viewport, things seem to slow down quite a bit, averaging 5.7 ms
per frame. This is even when the identical movie is fed to both stimuli.
Might there be a speed advantage in setting up two separate viewports
instead?
For anyone's reference, I've attached the current code I have for
playing a raw movie from a file.
On another note, in FrameTimer() in VisionEgg.Core, you might want to
consider replacing the word "frame" with "inter frame interval" or
"IFI":
Mean frame was 5.00 msec (200.01 fps), longest frame was 6.52 msec.
to
Mean IFI was 5.00 msec (200.01 fps), longest IFI was 6.52 msec.
For the longest time, I wondered why the total population of the
histogram was always one less than the total number of displayed frames,
'til I finally clued in :)
Cheers,
Martin Spacek
PhD student, Graduate Program in Neuroscience
Dept. of Ophthalmology and Visual Sciences
University of British Columbia, Vancouver, BC, Canada
604-875-4555 ext. 66282
mspacek@xxxxxxxxxxxxxxx
http://swindale.ecc.ubc.ca
----- Original Message -----
From: "Andrew Straw" <astraw@xxxxxxxxxxx>
To: <visionegg@xxxxxxxxxxxxx>; <mspacek@xxxxxxxxxxxxxxx>
Sent: Saturday, September 18, 2004 1:09 PM
Subject: [visionegg] Re: Displaying raw movies
Dear Martin,
I just updated Textures.py to accept numarray data as a texel source.
I've updated CVS, and I attach the new files since SourceForge's CVS
mirrors are a little bit slow.
At some point, it would be good to support numarray more directly,
perhaps in a "both supported" approach like the numerix module of
matplotlib
Please let me know if this does not address your issue -- your task is
an important one to get right.
Finally, I've recently become aware of the (not very well publicized)
buffer() builtin function to Python. I think it and its related C API
might be useful in situations like yours, because they allow raw memory
access without many hoops. In fact, I should probably re-visit the
Vision Egg source code with this in mind...
Cheers!
Andrew
vsyncsperframe = 1
numgreyvsyncs = 400 # number of grey refreshes to display at start
scale = 2 # magification of checkerboard (this many screen pixels squared per
movie pixel)
##########################################
import VisionEgg, struct, numarray, os, gatoext, pygame
from VisionEgg.Core import *
from VisionEgg.Textures import *
VisionEgg.start_default_logging(); VisionEgg.watch_exceptions() # is this stuff
needed?
# Open a file for reading in binary format
buffersize = 122884096 # size on disk: 122884096 bytes, is this more ideal than
the default?
f = file("movie1.m", 'rb', buffersize)
# Read the first five bytes as a header string
header = f.read(5)
# The remaining fields are 2 byte unsigned integers
typecode = 'H' # 'H' is an unsigned short int, which is 2 bytes on this PC
(width,) = struct.unpack(typecode, f.read(2))
(height,) = struct.unpack(typecode, f.read(2))
(numframes,) = struct.unpack(typecode, f.read(2))
print "header =", header
print "width =", width
print "height =", height
print "numframes =", numframes
# Read in the movie data as 8 bit unsigned integers from the file
movie = numarray.fromfile(f, numarray.UInt8, (numframes,height,width)) #
indices in Python numarray are (z,y,x)==(hyperdim,row,column)
print "Done reading"
movie = movie[::,::-1,::] # flips the movie vertically for OpenGL's bottom left
origin
print "Done flipping"
'''
# Alternate code to read in data using much slower Numeric method
data = Numeric.array(f.read())
print "Done reading"
movie = Numeric.reshape(data,(numframes, width, height))
print "Done reshaping"
movie = movie[::,::-1,::]
print "Done flipping"
'''
# Check to see if there are any leftover bytes in the file
stuff = f.read()
if stuff != '':
print "Error: There are unread bytes in the file. Width, height, or
numframes is incorrect in the header."
os.abort()
f.close() # Close the file
gatoext.olInitBoard() # Initialize DT340 digital output board
# Initialize OpenGL graphics screen.
screen = get_default_screen()
screen.parameters.bgcolor = (0.5,0.5,0.5,0.0) # set the background color to
grey (RGBA).
checkerboard_size=(height,width)
scaled_size = (scale*checkerboard_size[0],scale*checkerboard_size[1])
# Create an instance of the texture class, start with a grey frame
greyframe = numarray.zeros([width,height]) + 127
temp_texture = Texture(greyframe)
checkerboard = TextureStimulus(texture=temp_texture,
position=(400,300),
anchor="center",
mipmaps_enabled=0,
size=scaled_size,
texture_min_filter=gl.GL_NEAREST,
texture_mag_filter=gl.GL_NEAREST
)
# Create a Viewport instance
viewport = Viewport(screen=screen, stimuli=[checkerboard])
texture_object = checkerboard.parameters.texture.get_texture_object()
# Display the grey frame for the specified number of vsyncs
greyvsyncnum = 0 # 0 based
quit = 0
pause = 0
grey_frame_timer = FrameTimer()
while greyvsyncnum < numgreyvsyncs:
for eventi in pygame.event.get(): # for all events in the event queue
if eventi.type == pygame.locals.KEYDOWN:
if eventi.key == pygame.locals.K_ESCAPE:
quit = 1
if eventi.key == pygame.locals.K_PAUSE:
pause = int(not pause) # toggle pause
if quit:
break
elif pause:
continue
screen.clear()
viewport.draw()
swap_buffers()
grey_frame_timer.tick()
greyvsyncnum += 1
grey_frame_timer.log_histogram()
# Main loop
vsyncnum = 0 # 0 based
framenum = 0 # 0 based
quit = 0
pause = 0
frame_timer = FrameTimer()
while framenum <= numframes-1: # numframes is 1 based
for eventi in pygame.event.get(): # for all events in the event queue
if eventi.type == pygame.locals.KEYDOWN:
if eventi.key == pygame.locals.K_ESCAPE:
quit = 1
if eventi.key == pygame.locals.K_PAUSE:
pause = int(not pause) # toggle pause
if quit:
break
elif pause:
continue
# shouldn't use mod, messes up on the last frame, use another counter
instead
if (vsyncnum % vsyncsperframe)==0: # if vsyncnum is a multiple of
vsyncsperframe
texture_object.put_sub_image(movie[framenum,0:width,0:height]) # load
next frame
framenum += 1
screen.clear()
viewport.draw()
swap_buffers()
gatoext.olPostValue(framenum)
frame_timer.tick()
vsyncnum += 1
gatoext.olPostValue(0) # set all DT340 board lines to low
gatoext.olCloseBoard() # close DT340 board
frame_timer.log_histogram()
- Follow-Ups:
- [visionegg] Re: Displaying raw movies
- From: Andrew Straw
- References:
- [visionegg] Displaying raw movies
- From: Martin Spacek
- [visionegg] Re: Displaying raw movies
- From: Andrew Straw
Other related posts:
- » [visionegg] Displaying raw movies
- » [visionegg] Re: Displaying raw movies
- » [visionegg] Re: Displaying raw movies
- » [visionegg] Re: Displaying raw movies
- [visionegg] Re: Displaying raw movies
- From: Andrew Straw
- [visionegg] Displaying raw movies
- From: Martin Spacek
- [visionegg] Re: Displaying raw movies
- From: Andrew Straw