|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectjava.awt.Component
org.dvb.ui.BufferedAnimation
public class BufferedAnimation
A BufferedAnimation
is an AWT component that maintains a queue
of one or more image buffers. This permits efficient flicker-free
animation by allowing a caller to draw to an off-screen buffer,
which the system then copies to the framebuffer in coordination with
the video output subsystem. This class also allows an application
to request a series of buffers, so that it can get a small number
of frames ahead in an animation. This allows an application to
be robust in the presence of short delays, e.g. from garbage collection.
A relatively small number of buffers is recommended, perhaps three or
four. A BufferedAnimation with one buffer provides little or no protection
from pauses, but does provide double-buffered animation.
This class can be used for frame-synchronous animation. When animation
is in progress, it maintains a count of the frame number in the underlying
video output device. This frame number increases monotonically by one
for each video frame output. It is not influenced by trick play of any
video that might be playing on the same screen. However, the framerate
of the BufferedAnimation
may be
determined by the framerate of such
video; see setFramerate(float)
and
getFramerate()
for details.
The implementation shall prevent tearing artifacts whenever possible. The maximum size and animation rate that can be achieved without tearing artifacts may be specified by the system model of a specification that includes this class. If it is necessary to avoid a tearing artifact, an implementation shall delay the copying of an internal buffer to the frame buffer by up to one frame.
The size of this component is set using the normal AWT mechanisms.
When the method setBuffers(Dimension, int, boolean, boolean)
is called,
initialization is performed. At this time, the size of the
graphics buffers is set.
When one of this component's buffers is copied to the frame buffer,
it is done without regard to any AWT components which may overlap with
this component. This is like the behavior when an application draws
directly to the screen using a graphics object obtained with
java.awt.Component.getGraphics().
When the system copies a buffer to the frame buffer for a given
frame f, it shall select the valid buffer associated with
the highest-numbered frame fb such that
fb <= f. A buffer is valid if
startFrame(int)
has been called for that buffer,
finishFrame(int)
has been called, and the given buffer has not been re-used for
a subsequent frame as a result of another call to
startFrame(int)
.
The animation task proceeds at a high relative CPU priority, and can
be considered to execute at a priority greater than Java's
Thread.NORM_PRIORITY
. However, when no new
image buffer is ready, the system task must always block until one
is. Drawing into the buffer is done within a Java thread, which is
subject to the normal scheduling guarantees. In this way, a CPU-bound
caller
can avoid starving more important activities, such as responding to
remote control input. CPU-bound applications may wish to invoke
Thread.yield()
after each frame, however, particularly
if the application's
animation thread is at the same priority level as other application
threads.
A component that is not visible and is in the started state will
run, but it will not display any buffers to the screen. It will
block in the call to startFrame()
until the component becomes visible,
or until it is too late to draw the requested frame, whichever comes
first. Once it is too late, it will, of course, return -1, thus
ensuring that the caller doesn't waste time drawing to an internal
graphics buffer that wouldnt' be displayed.
For the behavior when this component is destroyed, see
removeNotify()
.
Sample usage:
BufferedAnimation anim = new BufferedAnimation(); ... put anim in a component hierarchy Dimension d = new Dimension(...); int numBuffers = 4; for (;;) { try { anim.setBuffers(d, 4, false, true); break; } catch (OutOfMemoryError err) { ... try smaller buffers, or fewer of them } } ... set framerate, if needed ... Make anim visible Graphics2D[] bufs = anim.getBuffersGraphics(); anim.startAnimation(); // Animate 1000 frames... try { for (int f = 0; f < 1000; f++) { int n; try { n = anim.startFrame(f); // blocks until a buffer is free } catch (InterruptedException ex) { // someone else called stopAnimation. or removeNotify() was // called. In any case, we're being asked to stop the // animation immediately. break; } if (n > -1) { try { myDrawFrame(f, bufs[n]); } finally { anim.finishFrame(f); } } } } finally { anim.stopAnimation(false); }
This class does not specify a return value for
Component.isDoubleBuffered()
. That method
reports on a different
kind of buffering, related to the repaint()
call. BufferedAnimation
objects might or might not be double-buffered, in the repaint-related
sense meant by Component.isDoubleBuffered()
.
NOTE: A future version of this API could potentially allow simultaneous drawing to two frames, by relaxing the synchronization condition on startFrame(int). However, it is unclear if this would yield benefits e.g. on a multi-core system, given memory bandwith limitations and the already existing ability to have parallel threads drawing into one frame or doing other computations.
Field Summary | |
---|---|
static float |
FRAME_23_98
Constant representing a common video framerate, approximately 23.98 frames per second, and equal to 24000f/1001f . |
static float |
FRAME_24
Constant representing a common video framerate, equal to 24f . |
static float |
FRAME_25
Constant representing a common video framerate, equal to 25f . |
static float |
FRAME_29_97
Constant representing a common video framerate, approximately 29.97 frames per second, and equal to 30000f/1001f . |
static float |
FRAME_50
Constant representing a common video framerate, equal to 50f . |
static float |
FRAME_59_94
Constant representing a common video framerate, approximately 59.94 frames per second, and equal to 60000f/1001f . |
Fields inherited from class java.awt.Component |
---|
BOTTOM_ALIGNMENT, CENTER_ALIGNMENT, LEFT_ALIGNMENT, RIGHT_ALIGNMENT, TOP_ALIGNMENT |
Fields inherited from interface java.awt.image.ImageObserver |
---|
ABORT, ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, WIDTH |
Constructor Summary | |
---|---|
BufferedAnimation()
Create a new BufferedAnimation component. |
Method Summary | |
---|---|
void |
addNotify()
Makes this Component displayable by connecting
it to a native screen resource. |
void |
finishFrame(int frameNumber)
Notify the system that the frame currently being drawn is finished. |
java.awt.Graphics2D[] |
getBuffersGraphics()
Get the graphics objects for drawing into this component's internal image buffers. |
java.awt.Dimension |
getBuffersSize()
Get the size of the internal image buffers. |
float |
getFramerate()
Get the actual framerate of the screen associated with this component. |
long |
getMediaTime(javax.media.Clock c,
int frameNumber)
Get the predicted media time of the given frameNumber for this animation. |
boolean |
isStarted()
Return true if this animation is started. |
void |
paint(java.awt.Graphics g)
If this component has an active animation, then this method paints either the last valid image buffer or the next valid image buffer to the given graphics object. |
void |
removeNotify()
Make this component undisplayable by destroying any native resources, and freeing its image buffers. |
void |
setBuffers(java.awt.Dimension bufSize,
int numBuffers,
boolean forceSize,
boolean forceAcceleration)
Set the size and number of the internal image buffers. |
void |
setFramerate(float rate)
Attempt to set the framerate of the screen associated with this component. |
void |
startAnimation()
Start this animation immediately, and reset the frame number to zero. |
void |
startAnimationAt(javax.media.Clock c,
javax.media.Time t)
Start this animation keyed to the clock at the given media time. |
int |
startFrame(int frameNumber)
Start drawing the given frame. |
void |
stopAnimation(boolean immediate)
Stops this animation. |
Methods inherited from class java.awt.Component |
---|
action, add, addComponentListener, addFocusListener, addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addMouseWheelListener, addPropertyChangeListener, addPropertyChangeListener, applyComponentOrientation, areFocusTraversalKeysSet, bounds, checkImage, checkImage, contains, contains, createImage, createImage, createVolatileImage, createVolatileImage, deliverEvent, disable, dispatchEvent, doLayout, enable, enable, enableInputMethods, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, firePropertyChange, getAccessibleContext, getAlignmentX, getAlignmentY, getBackground, getBounds, getBounds, getColorModel, getComponentAt, getComponentAt, getComponentListeners, getComponentOrientation, getCursor, getDropTarget, getFocusCycleRootAncestor, getFocusListeners, getFocusTraversalKeys, getFocusTraversalKeysEnabled, getFont, getFontMetrics, getForeground, getGraphics, getGraphicsConfiguration, getHeight, getHierarchyBoundsListeners, getHierarchyListeners, getIgnoreRepaint, getInputContext, getInputMethodListeners, getInputMethodRequests, getKeyListeners, getListeners, getLocale, getLocation, getLocation, getLocationOnScreen, getMaximumSize, getMinimumSize, getMouseListeners, getMouseMotionListeners, getMousePosition, getMouseWheelListeners, getName, getParent, getPeer, getPreferredSize, getPropertyChangeListeners, getPropertyChangeListeners, getSize, getSize, getToolkit, getTreeLock, getWidth, getX, getY, gotFocus, handleEvent, hasFocus, hide, imageUpdate, inside, invalidate, isBackgroundSet, isCursorSet, isDisplayable, isDoubleBuffered, isEnabled, isFocusable, isFocusCycleRoot, isFocusOwner, isFocusTraversable, isFontSet, isForegroundSet, isLightweight, isMaximumSizeSet, isMinimumSizeSet, isOpaque, isPreferredSizeSet, isShowing, isValid, isVisible, keyDown, keyUp, layout, list, list, list, list, list, locate, location, lostFocus, minimumSize, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paintAll, postEvent, preferredSize, prepareImage, prepareImage, print, printAll, remove, removeComponentListener, removeFocusListener, removeHierarchyBoundsListener, removeHierarchyListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removeMouseWheelListener, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, repaint, requestFocus, requestFocusInWindow, reshape, resize, resize, setBackground, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setEnabled, setFocusable, setFocusTraversalKeys, setFocusTraversalKeysEnabled, setFont, setForeground, setIgnoreRepaint, setLocale, setLocation, setLocation, setMaximumSize, setMinimumSize, setName, setPreferredSize, setSize, setSize, setVisible, show, show, size, toString, transferFocus, transferFocusBackward, transferFocusUpCycle, update, validate |
Methods inherited from class java.lang.Object |
---|
equals, getClass, hashCode, notify, notifyAll, wait, wait, wait |
Field Detail |
---|
public static float FRAME_23_98
24000f/1001f
.
getFramerate()
,
setFramerate(float)
public static float FRAME_24
24f
.
getFramerate()
,
setFramerate(float)
public static float FRAME_25
25f
.
getFramerate()
,
setFramerate(float)
public static float FRAME_29_97
30000f/1001f
.
getFramerate()
,
setFramerate(float)
public static float FRAME_50
50f
.
getFramerate()
,
setFramerate(float)
public static float FRAME_59_94
60000f/1001f
.
getFramerate()
,
setFramerate(float)
Constructor Detail |
---|
public BufferedAnimation()
BufferedAnimation
component. The
BufferedAnimation functionality may be optional. Applications
written to device specifications that do not make this functionality
mandatory should be prepared to catch UnsupportedOperationException
when invoking this constructor.
java.lang.UnsupportedOperationException
- If this feature is not supported on the device.Method Detail |
---|
public void setBuffers(java.awt.Dimension bufSize, int numBuffers, boolean forceSize, boolean forceAcceleration)
BufferedAnimation
's buffers to the
component's size in real-time, then the internal buffers will
be of the requested size, and scaling will occur. If the system
is not, then the results will depend on the value of
forceSize
.
On a system that cannot perform a requested scaling, if
forceSize
is true,
then the buffers' sizes will be set to the requested size
regardless. The displayed result will be clipped or will
have areas that are unpainted, as needed. In all cases, the
upper-left hand corner of the buffers will be painted at
to the upper-left hand corner of the component.
On a system that cannot perform scaling, if
forceSize
is false,
the buffers' size will be set to the current size of the component.
That is, the requested buffer dimension will be ignored.
The system model of specifications that include this class may specify a set of supported scalings.
Note that the framebuffer itself might be scaled for display on the output device. For example, a specification including this class might include half-resolution mode, e.g. for half-resolution computer graphics over 1080i video.
Graphics Acceleration
Some systems have special faster video memory that gives accelerated
graphics performance. The system model of a specification adopting
this API may define a minimum amount of such memory. Other hardware
architectures, such as "unified memory architecture" platforms,
don't have special accelerated memory. On these platforms,
all video memory is considered "accelerated", that is, the
forceAccelerated
parameter has no effect, and does
not cause automatic failure.
On platforms with special accelerated video memory, the caller may
indicate
that all of the graphics buffers must be allocated from this
accelerated memory. It does this by setting the
forceAcceleration
parameter true. This may make an OutOfMemoryError more likely.
If forceAcceleration is not true, then the
implementation will make a "best-effort" attempt to put the buffers
in accelerated memory, but will fall back to normal heap memory,
if required.
This method may be called more than once. If it exits with an exception, the state of this object will not be changed. If it returns normally, the new values will override anything set previously.
bufSize
- The requested buffer sizenumBuffers
- The number of image buffers to allocateforceSize
- Force sizing the buffers to the requested size,
even if this means clipping or having unpainted
areas.forceAcceleration
- Force allocation of all buffers in accelerated
memory.
java.lang.IllegalArgumentException
- if d.width or d.height is less
than one, or numBuffers is less
than one.
java.lang.IllegalStateException
- if getBuffersGraphics has been called
for this component.
java.lang.IllegalStateException
- If this component isn't displayable.
OutOfMemoryException
- If there isn't enough memory to allocate
the needed buffers.Component.isDisplayable()
public java.awt.Graphics2D[] getBuffersGraphics()
setBuffers
method.
After the first call, subsequent invocations of this method shall
return the identical value (i.e. multiple calls will return values
that are ==
to each other).
Other than the setBuffers
mechanism,
the size of the internal
buffers will never change. If the component is resized, the
system might scale the resulting animation, but this behavior
is not guaranteed by the specification of this class. In all
cases, the upper-left hand corner
of the image buffer will be displayed in the upper-left hand
corner of the component.
The initial contents of the graphics buffers is undefined. Callers
may wish to initialize the buffers to a known state, such as fully
transparent, before starting an animation. Once an animation is
started, drawing into a buffer outside of a
startFrame/finishFrame
pair may produce unpredictable
results on the screen.
java.lang.IllegalStateException
- if the setBuffers()
hasn't
been successfully called.setBuffers(java.awt.Dimension, int, boolean, boolean)
public java.awt.Dimension getBuffersSize()
getBuffersGraphics()
,
setBuffers(java.awt.Dimension, int, boolean, boolean)
public void paint(java.awt.Graphics g)
startFrame/finishFrame
sequence is in progress, this method will block until
finishFrame
is called, thus generating a valid image buffer. If no animation
is in progress or no valid frames have yet been generated, then
this method does nothing.
Note that in normal operation, this method should be called by
the platform very infrequently, if at all. It might be called, for
example, due to an "expose event," or due to a call to
Component.print(Graphics)
. Application authors should not
request a call to paint
via the repaint mechanism to animate
this component, because this class uses a different model for
animation.
paint
in class java.awt.Component
public int startFrame(int frameNumber) throws java.lang.InterruptedException
getBuffersGraphics()
for drawing of this frame, or -1 if the animation has fallen
behind, and a later frame should now be drawn. After calling
this method, if a value other than -1 is returned, the
caller may draw to the indicated graphics buffer. When it is
finished, it shall call finishFrame()
.
If a buffer is not available for the given frame, this method will block until one is ready.
The caller can always skip frames. For example, a caller wishing to animate at half of the component's framerate could request frames 0, 2, 4, 6, 8, 10, etc. In this example, if there are four buffers and animation does not fall behind, the caller would be instructed to draw into buffer 0, 1, 2, 3, 0, 1, etc. A caller that wishes to start animating at a frame greater than 0 may do so by simply starting with a number greater than zero; when the lower-numbered frames are being presented, the component will simply do no drawing.
The content of the framebuffers is not modified by the system. Thus, a caller that is drawing into buffer number n could function correctly if it only drew to pixels that have changed since it last drew into buffer number n.
frameNumber
- The frame number to draw. The first frame
is frame 0.
java.lang.IllegalArgumentException
- if frameNumber is less than or
equal to a number previously
supplied to this animation, or is
less than zero.
java.lang.IllegalStateException
- if startFrame()
has already been
successfully
called without a corresponding
finishFrame()
.
java.lang.InterruptedException
- If this animation is in the stopped
state, either when this method is called
or due to a state transition while
it is blocked waiting for a
graphics buffer.getBuffersGraphics()
,
isStarted()
public void finishFrame(int frameNumber)
startFrame(int)
.
Once finishFrame(int)
is called,
the system can copy that frame to
the framebuffer, and the caller can move on to preparing the next
frame.
frameNumber
- The frame number that is finished. This must
match the value passed into startFrame(int).
java.lang.IllegalStateException
- if a startFrame call has not returned
successfully for the given frame number
(with a return value other
than -1), if
finishFrame(int)
has
already been called for this frame
number since the startFrame call, or if
stopAnimation(boolean)
has been called since the corresponding
startFrame call.startFrame(int)
public void setFramerate(float rate)
The system model of specifications including this class might
determine under what conditions the framerate can be set, and
what framerates are guaranteed to be supported. This class
defines a number of common framerates as constants whose name
begin with "FRAME_
".
Note that an application that wishes to animate at a lower framerate
than that of the hardware may do so, by simply skipping frames. This
is discussed in the startFrame(int)
method.
java.lang.IllegalStateException
- If this component is not displayable.Component.isDisplayable()
,
startFrame(int)
public float getFramerate()
FRAME_
".
public void startAnimation()
Applications should only call this method on a stopped animation.
However, if this method is called when an animation is already started,
it is re-started; the effect is equivalent to calling
stopAnimation(true)
followed by
startAnimation()
.
isStarted()
public void startAnimationAt(javax.media.Clock c, javax.media.Time t) throws javax.media.IncompatibleTimeBaseException
startAnimation()
. Otherwise,
once the clock's media time is greater than or equal to the given
the given value, the animation will be started. Callers should
not assume that frame zero of the animation will coincide with the
desired time in all cases; for example, the clock's media time might
advance in a discontinuous manner. Callers should always consult
getMediaTime(...)
.
This method can be used to initiate frame-accurate animation that is synchronized to video that is being presented on the same screen. The animation enters the started state, and drawing to graphics buffers can begin. The system will start copying these buffers to the framebuffer automatically, when the clock reaches the given time.
Subsequent calls to this method override any previous calls.
If this method is called when an animation is already started,
it is re-started; the effect is equivlanet to calling
stopAnimation(true)
followed by
startAnimationAt(...)
.
c
- A JMF Clock that is associated with some media.t
- A media time of that clock when the
animation should start.
javax.media.IncompatibleTimeBaseException
- If this Clock is incompatible with this animation.
This will never be thrown if the Clock is associated
with video being displayed on the same screen as
this animation.
java.lang.IllegalStateException
- If this clock is not in the started state.isStarted()
,
getMediaTime(javax.media.Clock, int)
public void stopAnimation(boolean immediate)
paint()
method.
The caller may request that queued fames of animation be output to the screen. This will be done if the animation is in the started state, and immediate is set false.
If a successful call to startFrame(int)
has not yet
been matched with a call to finishFrame(int)
, this
object is set to the stopped state, which will cause
finishFrame(int)
ti fail. See that method for details.
After this method returns, isStarted()
will return false.
If this animation is not in the started state, calling this method
will have no effect.
immediate
- If the component should immediately stop copying
buffers to the screen,
instead of letting any queued animation frames
be output.isStarted()
,
finishFrame(int)
public boolean isStarted()
BufferedAnimation
can either be in the started or stopped state. A stopped
BufferedAnimation
will only draw to the framebuffer
if it is in the process of flushing animation buffers due to a
call to stopAnimation(false)
BufferedAnimation
is
started, false otherwise.stopAnimation(boolean)
public long getMediaTime(javax.media.Clock c, int frameNumber)
The return value can be converted into a javax.media.Time
value by calling the javax.media.Time(long)
constructor.
This method is useful for keeping an animation aligned with a video source, even if "trick play" operations cause the media position to change. Note that because the computer generated animation might be a small number of frames "ahead" of the video due to the buffering this class provides, there might be a perceptable "lag" during trick play itself, but once the video returns to normal play mode, the animation would once again be frame-synchronized.
c
- The clock to calculate media time relative toframeNumber
- the desired frame number of this animation
java.lang.IllegalStateException
- if this animation is not in the
started state.
javax.media.IncompatibleTimeBaseException
- If this Clock is incompatible with this animation.
This will never be thrown if the Clock is associated
with video being displayed on the same screen as
this BufferedAnimation
component.
java.lang.IllegalStateException
- If this clock is not in the started state.public void removeNotify()
stopAnimation(true)
shall be called by the implementation of this method.
removeNotify
in class java.awt.Component
public void addNotify()
Component
displayable by connecting
it to a native screen resource. This method is called
internally by the toolkit and should not be called directly
by programs.
addNotify
in class java.awt.Component
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |