We hit a snag the other day with the development of Tiny Ears. Our strategy to save space on the animation in each storybook was to create lightweight movies to play at the appropriate moment, rather than to have to implement large quantities of frame animation with all of the assets involved (including now retina support with the new iPad). To save further space we decided that we would like to animate only those things that moved by creating a video animation with an alpha channel to make the background visible through the video.
Problem was, when it came to implementing this strategy on the device itself, the transparent .mov file renders with a black background. Why? AVPlayer and MPMoviePlayer do not have alpha channel support. Desperate not to have to change our strategy and recreate our animations complete with background or return to frame animation I spent some time researching a possible solution on the Internet. After 1 day of looking the best I had come up with was a solution suggesting we use OpenGL to sample the video as it played and turn certain colours transparent I was ready to give it up for lost.
Then, at last, I came across AVAnimator. Hidden in the depths of Google lay this single page site detailing this wonderful library that seems to do pretty much everything that you would want to do with movies in iOS but can’t. There is little documentation and that single page is the only information that exists, but it was enough. Here was a native movie player for iOS with alpha channel support (and a lot more besides but we won’t go into that now).
The code itself was really simple to implement, but in order to play the movies you have to do a little bit of transformation first to turn them into the .mvid format that AVAnimator requires. The tools you need are qtexportani and QTFileParser.
Unpack qtexportani. Open a terminal in that location and type the following:
This will create you a file in the same directory called export_<name>.mov.
Now unzip QTFile112.zip. Go into QTFileParser and open the XCode project. Build & archive the app and select Distribute. Select Save Built Products and choose somewhere to save it. Then, with the terminal in the same location as the app you just built, run the following command:
./qtaniframes -mvid export_<name>.mov
This will save you a file called export_<name>.mvid.
At this point, don’t be afraid of the fact that your new .mvid file is substantially larger than the original .mov. We’re gonna 7Zip it to make it nice and small. The nice thing about AVAnimator is that you can 7Zip all of your .mvid media into one archive and use that in your app, making all of your media have a delightfully small footprint. I’m not gonna tell you how to 7Zip your files – you’re geeks you should be able to handle that on your own. But at the end of it you should have something like <name>.7z that contains all of your mvid media.
Now comes the fun bit. From the AVAnimator site I could not find just the source file download, but you can grab it by downloading any of the links from their website. I grabbed StreetFighter cos that was the example app that did exactly what I wanted.
So, in your xcodeproj, import all of the files in the AVAnimator folder that you will find in your downloaded project. You will also need to import all the files inside the folder called LZMASDK. In the UIViewController where you want to play your animation then add the following code:
// create the animator view
AVAnimatorView *animationView = [AVAnimatorView aVAnimatorViewWithFrame:CGRectMake(0,0,1024,768)];
// create a new object to store your media in
AVAnimatorMedia *media = [AVAnimatorMedia aVAnimatorMedia];
// Create a 7Zip resource loader
AV7zAppResourceLoader *resLoader = [AV7zAppResourceLoader aV7zAppResourceLoader];
// tell the resource loader what the name of your 7Zip archive is, and the name of the media file inside it you want to play
resLoader.archiveFilename = @”media.7z”;
resLoader.movieFilename = @”export_video.mvid”;
resLoader.outPath = [AVFileUtil getTmpDirPath:animationFilename];
// tell the media holder which resource loader to use
media.resourceLoader = resLoader;
// Create decoder that will generate frames from Quicktime Animation encoded data
AVMvidFrameDecoder *frameDecoder = [AVMvidFrameDecoder aVMvidFrameDecoder];
media.frameDecoder = frameDecoder;
media.animatorFrameDuration = AVAnimator30FPS; // this is a constant I made for the frame rate
// request to be notified when the movie is played
[[NSNotificationCenter defaultCenter] addObserver:self
// you have to add the AVAnimatorView to the superview before you can attach the AVAnimatorMedia
// play the movie
And that’s it. Everything to you need to play a movie animation while preserving the alpha channel creating a transparent animation. In a few short lines of code. Thank you AVAnimator, you wonderful thing you. It’s astounding that more people don’t know you exist.