views:

208

answers:

5

I'm working on a standalone Flash application (written using Flex 3/ActionScript 3) that features a text crawl, like what you might see at the bottom of your TV when watching a cable news channel; it's a long narrow box that text moves across from right to left.

I've implemented it by creating a Label element, populating it with text, and then moving it using a mx:Move object with a Linear.easeNone easing function. It works, but it has ample room for improvement. It looks a bit jerky, and tends to have a fair amount of "tearing" (the top and bottom halves of the text sometimes fall out of sync).

I tried throwing math at the problem to get the crawl's movement rate synced with the monitor's refresh rate, but that was a bust. I found out the hard way that the app's frame rate jumps around too much; the "optimized" crawl varied between looking silky smooth and like it had epilepsy.

Is there anything else folks would recommend I try to smooth this thing out? Is there some alternate design you'd recommend I try?


Edit: Some context: the crawl is part of a digital signage application (played from a standalone Flash projector -- no web browser) that does stuff elsewhere on the screen, including video playback and rendering text and images. It definitely gets choppier during video playback, but it's never as smooth as I'd like it to be.

A: 

TweenMax or even TweenLite ( http://www.greensock.com )handles this sort of job pretty well. What else is your app doing while the text is scrolling though? Is it possible that some other processes are interfering?

PatrickS
Could other processes be interfering? Oh, heck yes. Another display panel cycles through images and occasionally runs videos. Another occasionally downloads RSS feeds and displays the text. There's plenty going on.
BlairHippo
Thanks for the effort, but I just downloaded and got done playing with TweenMax/TweenLite, and it's a bust. For some reason, those packages REALLY don't like my code; the app only plays properly about one time in five when I'm using either of them. And when it does play, the crawl is noticeably choppier than it was before.
BlairHippo
A: 

This may not be helpful, but have you considered putting the crawling text into the html DOM and using CSS transitions to crawl the text. Obviously there's the IE problem, but it should be supported in IE9 and you could use javascript as a fallback.

This may seem silly, but CSS transitions are getting hardware acceleration and separate processes for plugins meaning on a multicore machine you could get parallel threads.

Russell Leggett
IE9? they're getting the though versions quick ;)
Sam
Thanks, but no go. It runs in a standalone flash projector, not inside a browser.
BlairHippo
+5  A: 

There are two potential solutions to this problem, but both have caveats, the first because of your use of Flex and a standalone projector, the second because it is a mitigator, not a complete solution.


Hardware Acceleration

When publishing your file, you can attempt to have Flash utilize hardware acceleration to alleviate the vertical refresh issue you are running into that is causing tearing. Sadly, Flex Builder 3 is incapable of enabling this setting at the SWF (projector) level (Link to bug). This has yet to be resolved and has been pushed from 4.0 to 4.1 to 4.x... If and when it is resolved, it will likely be a compiler argument in the project settings of Flash Builder 4.

You may be able to determine if this solution works for you by outputting your projector as a standard SWF and embedding it on an HTML document with the wmode set to "direct" or "gpu". Sadly, if it does (it should), you can't use it right now anyway. If you have Flash Builder 4, certain projects are capable of making round trips between FB4 and Flash Professional CS5, though I am not sure what the criteria for that is (my current AIR project has all the project modification menu options grayed out). If you do manage to get your project into Flash, you can enable hardware acceleration in the Publish Settings of the project (File->Publish Settings->Flash tab->Hardware Acceleration option in CS5).

This method is almost a certain solution for your problem, though it has two issues, one already highlighted above, and (for people publishing for the web) that by utilizing direct or GPU rendering on a webpage, you are unable to layer any DOM elements on top of flash.

direct: This mode tries to use the fastest path to screen, or direct path if you will. In most cases it will ignore whatever the browser would want to do to have things like overlapping HTML menus or such work. A typical use case for this mode is video playback. On Windows this mode is using DirectDraw or Direct3D on Vista, on OSX and Linux we are using OpenGL. Fidelity should not be affected when you use this mode.

gpu: This is fully fledged compositing (+some extras) using some functionality of the graphics card. Think of it being similar to what OSX and Vista do for their desktop managers, the content of windows (in flash language that means movie clips) is still rendered using software, but the result is composited using hardware. When possible we also scale video natively in the card. More and more parts of our software rasterizer might move to the GPU over the next few Flash Player versions, this is just a start. On Windows this mode uses Direct3D, on OSX and Linux we are using OpenGL.

*Source

Direct is the ideal option for this situation, as you can actually have performance degredation with "gpu" as well as visual differences from graphics card to graphics card.

Lower your framerate

The Flash player will continue to play video at its native refresh rate independent of the rest of your project as long as you keep the framerate at or above approximately 2FPS (though I suggest 5FPS minimum). You won't want to run that low for this example, but you are able to lower the framerate of the entire scene without impacting video performance. The closer your framerate is to the screen refresh rate, the more apt you are to actually create the tearing effect unless you are able to absolutely sync with the monitor's refresh rate, which you probably cannot do without the above... Hardware Acceleration.


This problem has existed in the Flash Player for as long as it has been able to move objects horizontally. What happens is that Flash updates a buffered snapshot of the running animation at the same time that the screen is refreshing. If the buffered snapshot changes partway through a screen refresh, you get a tear. This is why lowering the framerate actually reduces the amount of tearing, you are refreshing the buffer less frequently.

Tegeril
With regard to it performing worse when a video appears on screen, it's likely that the video is increasing the overall framerate of the projector to that of the video while it is playing, increasing the number of buffer redraws, causing additional tearing.
Tegeril
This is, at the very least, a hell of a lot more insight into the problem than I had before. Thank you. But would it be accurate to summarize the section on Hardware Acceleration like this? "Someday, when Flex Builder sucks less, hardware acceleration may solve your problem. Today is not that day."
BlairHippo
In short, yes. In long, technically it's not Flash/Flex Builder's fault, because the application it uses to do the compilation (mxmlc) does not have it as a valid command line flag (or you could add it manually in the project settings). I just looked at the bug again and I'm concerned that it's marked as closed but deferred to 4.x. Perhaps they've... fixed it and it will make a future appearance? Though it is not listed as a known issue in the Flex SDK 4.0/4.1 release notes.
Tegeril
Addendum: Since it was originally reported by Colin Moock, one of the most influential names in ActionScript, I have a feeling it will be solved at some point...
Tegeril
Good news for the future, looks like someone else including myself got active on the bug and suddenly it's reopened, being assigned to the appropriate developer, and expected in the next release of Flex due out in 2011. Check the bug for updates.
Tegeril
A question: what does the number set to the "frameRate" property of "Application" signify? It's not frames per second. When I set it to 1, the application does indeed become comically choppy, but it's very definitely moving faster than a single frame per second.
BlairHippo
So, technically that is supposed to set the frame rate of the application in frames per second. I can't speak to the wide array of Flex Halo components, but I know that there is some level of independence from global frame rate (ie: the mention of video from before, you can run 2 or 3 FPS on <mx:Application> and the video will still play smoothly). I believe Flash has some precision issues running at such low frame rates, though I can't find any discussion of the issue online, it has something to do with needing to be at or above 2FPS for video to play smoothly despite it being independent.
Tegeril
This didn't completely solve the problem, but the clock was ticking for the bounty, and I felt Tegeril gave me the most insight into both the problem and ways of addressing it. My sincerest thanks for helping me out.
BlairHippo
Thanks, hopefully you are able to get it to a passable level of performance and that in the near future, you'll be able to compile with hardware acceleration (keep an eye on the bug).
Tegeril
+3  A: 

As @Tegeril mentioned, using Flex is one of the reasons. Flex is a pretty heavy framework and it does a lot of things behind the scenes. If you're familiar with the life cycle of a component(especially invalidating properties, invalidating the display list, etc.).

As a few minor things that might improve performance:

  • try to keep a simple display list. If you know the app will always be displayed at one size, then flex won't waste time traversing the display list/tree up to the top and back for measurements. Also, try to use a Canvas. I know, it's not very clean, but since it uses absolute values and doesn't check with the 'parents' much, it should be faster than other containers(like HBox,VBox, etc.)
  • try to display the video at it's full size(make sure the encoded video dimensions are right so there be any CPU cycles on resizing video

Ok, this was Flex stuff.

It might be very handy to read sencular's article on Asynchronous ActionScript Execution which explains how Flash Player handles updates and renders. async frames

Frames both execute ActionScript and render the screen

async frames streched

ActionScript taking a long time to complete delays rendering

I imagine the jerkiness is related to this. Also, I'm guessing you might get moments of smooth movement then sudden halts, every now and then, when Flash Player catches it's breath(Garbage Collector cleans up)

Victor Drâmbă article on “Multithreading” in Actionscript might also be useful.

Soo, to recap:

  • use Profiler or something and see if the Flex framework is slowing you down, or where the 'bottleneck' is
  • improve as much as you can on that side then check if it's how Flash Player handles all the actionscript('elastic' frames)

If the bottleneck comes from the Flex framework, worst case, you can try to minimise the number of components that traverse the display list, and use pure actionscript for the other things(as @PatrickS suggested, use TweenLite, etc.)

If it helps, try to preload data(fetch rss feed and all that) at the start, and when you've got most of the important bits that don't require 'refreshes'/loads frequently, display the app. You will use more memory, but will have more cpu cycles to spare for other tasks. Also, if it's display objects that are the 'bottleneck' and there's plenty of them, check if you can reuse them using Object Pools.

HTH

George Profenza
These kinds of optimizations may definitely help with overall load of the application to mitigate performance loss as a result of the application being (seemingly) CPU intensive. This may also have a synergy of helping to keep buffer delays from occurring and may help mitigate buffer refreshes during GPU<->Screen refreshes. I would still see if you can lower your framerate without impacting visual smoothness and see if the combination of effects can bring the tearing down to an acceptable level. Beyond that, we need GPU acceleration in mxmlc.
Tegeril
Additionally, my assumption here is that this solution was to help solve overall performance and not tearing, because tearing will happen regardless of whether ActionScript is delaying a render or not unless you are using GPU rendering. If the performance fluctuations are fixed with this solution, you may also suddenly see more -regular- tearing, by which I mean, it will tear at regular intervals instead of randomly more and less over time if all of your frames are rendering in time without FPS slowdown.
Tegeril
My thanks for the information; anything that helps me understand the underlying issues is a Very Good Thing.
BlairHippo
@BlairHippo no problemo!
George Profenza
A: 

One thing you might consider is to move your label incrementally using a Timer instead of an easing function. That way you can take advantage of the updateAfterEvent method to get smoother rendering. Here's a link to an article/video from Chet Haase (Adobe's Flex graphics dude) that explains usage along with an example app with code:

http://graphics-geek.blogspot.com/2010/04/video-event-performance-in-flex.html

Hope that helps.

Wade Mueller
Thanks much for the idea, but it's not an improvement. I actually wonder if updateAfterEvent() is integrated into the easing function already; as I said in another comment, the screen updates much more quickly than the alleged frame rate.
BlairHippo