How insane is it that there’s no way to seamlessly loop video in Flash? Very insane! That’s how!!!
Here’s my requirement : I have a lot of prerendered 3D animations that need to loop. Spinning objects and stuff. So I’ve converted them to FLV and I’m loading them in with that really fiddly NetStream and NetConnection stuff. And they need to just quietly spin away in the background not taking up too much processor time.
So ideally in old-school programming days, we’d have a nice image sequence sitting in our timeline that just animates away. But of course, they make the swfs HUGE.
If only there was a way of combining the small filesize of flvs along with the speed of rendering of image sequences… Well now there is!
After a good day or so of tearing my hair out, I now present to you… the VideoMovieClip! It’s just like a normal movieclip except it’s made out of an flv. So you can gotoAndPlay, nextFrame, stop, play just as though it was a movieclip!
How awesome is that!?? Except I haven’t quite got it working.
I’ve had a day or two of nightmares.
The first was a bug with drawing into a BitmapData from a video object. If you do a bitmapData.draw(myVideo) it draws the Video object at the same size as it was when you set it up, ignoring any subsequent resizing. So the trick is to wait until you get the metadata and then set up the Video at the size given. Except if you do that then you can’t take a snapshot of the video straight away so you lose the first frame. So I’ve had to set up a matrix than converts from the old size to the new size. Nightmare.
But the most nightmarish part is that with Flash Video, you have no way of finding out when frame has been rendered! And we need to know when each frame renders so we can record it into a bitmap. It’s SUCH a nightmare!
So why not use an ENTER_FRAME? Because, even if you match your swf’s framerate to the flv, the video playback seems to run independently from the movie! You can’t guarantee that you’ll get every frame. Nightmare.
So why not just pick up the flv framerate from the metadata and set up a timer that fires at the same interval as the framerate? Great idea! Except it seems that flv’s actual framerates can be completely different from the metadata! Nightmare.
But what I did notice is that you can check the NetStream’s time property. This is the time (in seconds) that the video has been playing. If you set up a timer on every milisecond and trace out the NetStream time you’ll notice that it doesn’t increment smoothly. It steps up every few mils. Could this mean that that’s when a new frame appears? Let’s try it and see…
So I got a handy system that checks the NetStream time every frame and snapshots the video! Yay! Except, if the Flash Player slows down at all or has one of its hissy little fits, you miss frames. And when you miss a frame, it’s too late! You can’t even tell the NetStream to go to a specific time, so we can pick it up again. (well you can but it will just go to the nearest keyframe) In fact, it’s even really hard to find out that we missed one at all! Nightmare!!!!
So now it logs when it misses a frame and just runs the video again, hoping to pick up the missing frames. But I was finding it was missing loads of frames and wrongly trying to capture too many frames on some videos. And then I realised, the NetStream.time hack only works if there’s no audio in the flv! Nightmare!
But here it is so far. What I’ve got is an flv with numbers on so I can check for dropped frames. The first time you see 3 seconds of numbers, it’s the flv playing, and we’re recording it. When the little versions appear that means it’s finished one pass. If they’re all recorded we’ll then be watching the bitmap sequence. You can tell it’s the bitmap sequence if it has the red background. Otherwise it’ll try again to fill in the missing numbers.
Click the mouse to try again (although i haven’t cleaned up so if you keep clicking your memory usage will stack up).
And let me know if it works for you!
And if you’re feeling incredibly brave, check out the source : videomovieclip.zip. And I’m sorry about the state of it! :$
So thanks to Tink (see comments) it turns out that all of my work was unnecessary! All you have to do is embed the flv on a timeline and it syncs perfectly with your framerate and can do all the movieclip stuff..! Just going to do some performance tests and get back to you…