iPhone App Video Out
Editor’s note: Rob Terrell wrote to tell us about a painless, elegant way to pull the video off the iPhone to be displayed on a monitor or projector. To quote Rob’s original article, we can “be like Steve, using our apps on our phone, with the display projected for all to see.”
How It Works
There’s a private API inside the iPhone SDK for video output. A class called MPTVOutWindow will display whatever it contains via the video output dock connector. Erica Sadun discovered this class and figured out how to use it.
I created a UIApplication category — an extension to the existing UIApplication class — that uses the MPTVOutWindow class to mirror the device display onto the TV display. Extending UIApplication with a category makes using this within an app seamless: drop the file into a project, recompile, and go.
It’s really just that easy, though there are a couple of caveats:
1. Apps that use this won’t be allowed into the App Store because it uses a couple of private APIs. But since you’re already an iPhone application developer, creating a private build for your own use is normal.
2. It doesn’t copy parts of the screen that belong to OpenGL.
Cables
Use the the same cable you’d use to watch videos from your iPhone on a TV using the dock connector. Apple’s sells them for $50; going off-brand drops the price to as low $15.
Headphone-jack video cables from older iPods do not work.
Usage
Add the file UIApplication+TVOut.m to your project and add the “MediaPlayer.framework” framework, which contains references to the private API we’re using.
Your code will need to start the TV output by calling [[UIApplication] sharedApplication] startTVOut];
In my test app, I call it from applicationDidFinishLaunching:. One thing to remember about applicationDidFinishLaunching: is that it gets called before the runloop starts, so your primary window isn’t on screen yet. I call it with a brief delay to give the runloop a chance to get going.
- (void)applicationDidFinishLaunching:(UIApplication*)application { // give the runloop a chance to start [[UIApplication sharedApplication] performSelector: @selector(startTVOut) withObject: nil afterDelay: .1]; }
That’s about all you need to do!
For the brave, the category can optionally start itself:
The code includes an override for a private method called reportAppLaunchFinished:. This undocumented method seems to get called after the app has finished loading. Being undocumented, I’m not really sure what it does, or what the negative consequences of overriding it has. As far as I can tell, it’s only used to clean up the Default.png display. I’ve commented out that method, since it’s a bit mysterious. But if you uncomment the method, it will automatically start the TV out display for you. No changes to your code needed!
Category Details
The application category handles everything necessary to mirror the device’s display:
The startTVOut method creates the MPTVoutWindow, adds the necessary subviews, rotates them to match your app’s orientation, and centers them to appear properly on the TV. A background thread copies the bits from your main display into a view in the MPTVOutWindow.
The frames per second are configurable via the #define at the top of the file. Twelve fps works well for me.
Mirroring Other Apps?
Since this code runs as part of your app, it stops running when your app stops running. So it’s not a general purpose full-time video mirroring solution.
However, using other private methods, it’s possible to launch other apps while your app remains running, thus mirroring whatever app is in front. I’ve managed to mirror Safari (launched using the private openURL:asPanel: method). I’m sure you can figure ways to mirror other apps using some of the private app launching methods.