iPhone App Video Mirroring

How can you show your app to a large group? What if you want to show an app to a client, an investor, or at a trade show? Extensive Googling reveals lots of people asking the question, but no good answer.

I’m the organizer of the Raleigh iPhone Developer’s Meetup and it’s basically impossible for our group’s members to demo their apps. The “crowd people around a phone” method breaks at around four people. And our last meetup had 20 people!

Why can’t we be like Steve, using our apps on our phone, with the display projected for all to see?

I have a solution, if you’re willing to make a special build of your app that’s not meant for the app store. No jailbreaking required! Although a willingness to use private methods is.

Update: There’s a new version for iOS 4.0 here: http://www.touchcentric.com/blog/archives/123

How It Works

Inside the iPhone SDK exists a private API for video output. A class called MPTVOutWindow will display whatever it contains via the video output dock connector. (Thanks to Erica Sadun who discovered this class and figured out how to use it!)

I created a UIApplication category (that is to say, an extension to the existing UIApplication class) that uses MPTVOutWindow to mirror the device display onto the TV display. The goal was to make it seamless — drop the file into a project, recompile, and go. And it’s really just that easy, with a couple of caveats.

Caveat #1: apps that use this won’t be allowed into the App Store. That’s because it uses a couple of private APIs (the MPTVOutWindow class and UIGetScreenImage()). But since you’re already an iPhone application developer, creating a private build for your own use is normal.

Caveat #2: it doesn’t copy parts of the screen that belong to OpenGL. The class could be extended to do that, if you needed to.

Update: actually, it works fine with OpenGL. I demoed an OpenGL game using this at about 20 fps.

Getting Started

First, get a video out cable. It’s the same cable you’d use to watch videos from your iPhone on a TV using the dock connector (note: headphone-jack video cables from older iPods do not work). Apple’s official cable, Apple Component AV Cable, is $50 for composite video. A similar cable is only $14.18 at MonoPrice.com. Component cables are also available. `

How To Use

Add the file UIApplication+TVOut.m to your project. Also, you’ll need the “MediaPlayer.framework” framework, which contains references to the private API we’re using.

Somewhere in your code you need to call start. Anytime after your app’s primary window has been created, call startTVOut:

     [[UIApplication] sharedApplication] startTVOut];

That’s about all you need to do. 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. (You can configure the frames per second in the #define at the top of the file. 12 fps works well for me.)

iPhone app displaying its output on a TV

iPhone app displaying its output on a TV

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];
}

And actually, you don’t even need to call startTVOut. The category can 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!

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.

Not for Public Consumption!

Since this uses private methods, it would almost certainly not survive Apple’s app review process. To avoid getting your app rejected, you should remove this code from your release builds. This is pretty easy — set the current target to Release and uncheck the checkbox next to the file’s name. Also, if you call startTVOut manually, you’ll need to put some #ifdefs around that call, so it won’t get compiled into release builds.

Great, Where’s the Code?

Grab the latest code from here:

http://groups.google.com/group/iphone-developers-nc/web/UIApplication_TVOut.m

If you have any comments or questions, feel free to email me.

– Rob



Tags: , , ,
This entry was posted on Friday, May 15th, 2009 at 1:51 pm and is filed under Cocoa Touch, iPhone Development. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

21 Responses to “iPhone App Video Mirroring”

  1. iPhone App Video Out

    [...] 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 [...]

  2. Lance Fetters

    In fact, it’s possible to do video-out purely via QuartzCore.framework, without linking to MediaPlayer.framework.

    (Please forgive any inaccuracies in the following explanation; it has been several months since I last worked on this.)

    At the QuartzCore level, every UIWindow is backed by a CAContextImpl, which itself contains a CALayer. CAContextImpl takes a list of options at initialization, one of which lets you select which output display to use: LCD or TVOut.

    In my TVOut extension I hook the creation of the CAContextImpl so that the application’s main window appears via video-out (instead of the LCD):

    http://code.google.com/p/iphone-tvout/source/browse/trunk/NonMirrored/ApplicationHooks.mm#62

    However, it should be possible to create a secondary CAContextImpl within an app to allow for mirroring (or some other purpose) using the following:

    NSDictionary *dict = [NSDictionary dictionaryWithObject:@"TVOut" forKey:@"displayName"];
    CAContextImpl *ci = [[objc_getClass("CAContextImpl") alloc] initRemoteWithOptions:dict];
    CALayer *layer = [[CALayer alloc] init];
    [ci setLayer:layer];

    … “layer” can then be used for drawing.

    Note that it might be necessary to specify the bounds of the CALayer to suit the video-out resolution (I believe 720×480 for iPhone, 640×480 for iPod Touch).

  3. Dan A.

    Just wondering, did you work on this for 3.0? I’ve seen online that others have done this for 2.2, and if you’ve worked this on the 3.0 SDK, that would be wonderful. I assume it did, since you worked this after the 3.0 release, but just checking!

  4. atom

    Hey There,

    This code is super cool, so I’ve tried quickly to link it to my code, but unfortunately I get an error:

    ld: duplicate symbol .objc_category_name_MPVideoView_tvout in /path/to/Objects-normal/armv6/UIApplication+TVOut.o and /path/to/Objects-normal/armv6/AtomFlowAppDelegate.o

    which doesn’t seem to make much sense to me. In the AppDelegate there is just an #include and the performSelector:withObject:afterDelay: error.

    Sorry to be a pain, but do u have any idea why?

    Cheers,

    Adam

  5. links for 2009-06-13 at adam hoyle presents suckmypixel

    [...] TouchCentric » iPhone App Video Mirroring How to mirror the video on the app onto a TV or Projector (tags: iphone objective-c tv hardware video) [...]

  6. Rob

    Yep, worked in 3.0 for me!

  7. Rob

    Sounds like you’ve got the definition for the category (the .m file) in the project twice.

  8. G

    yes, it works on 3.0. Thanks a lot for the great code. It can’t be any simpler than this. And I have managed to mirror Safari, but not other apps. Safari gets mirrored fine because safari is embeddable component (UIWebView), but when I launch other apps, my original app closes and stopping the video out.

    has anyone successfully able to mirror other apps ? If so, could you share your trick please ?

    thanks a ton!

  9. The Evil Boss

    Rob,
    Thanks a bunch for this code, it’s come in handy when developing a prototype app to illustrate the possibilities brought by the iPhone platform.
    It certainly works brilliantly when presenting on stage!

    I have modify the code to allow for on-the-fly UI orientation changes and touch indicators which show where the user is touching the screen.
    I’d be happy to contribute the changes back to you, but embarrassingly wasn’t able to locate your e-mail address. If you’re interested in my changes, please send me an e-mail.

    As a side note, the extra CPU power of the iPhone 3GS allows me to run at 20 frames per second with no issues.

  10. Tony

    Any idea why the mirrowView does not show in landscape when the device is rotated?

    Here is my code for autorotation –

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)x {
    return (x == UIInterfaceOrientationPortrait) || UIInterfaceOrientationIsLandscape(x);
    }

    You help is greatly appreciated.

  11. Aral Balkan

    Looking forward to seeing The Evil Boss’s additions :)

    On a side note: openURL:asPanel: appears to have been removed in 3.0 +. Any other tricks for mirroring Safari?

    Thanks!

  12. momo

    Hello Rob,

    wow thats pretty amazing, to have a code for that,…
    I am not a coder and have no clue how to program,
    but i have a question that i cannot get out of my head,
    and after reading your post i even more surprised…
    Why does apple not want to output video signals on apps or even better why do they not programm an app for video out? it is possible, the code is here and then the app will not survive Apple’s app review process. Why does apple do that? have you an answer? really sucks… i mean they are forcing people to jailbrake their ipods…

  13. Visionner les applications iPhone sur sa TV

    [...] Rob Terrell a développé une classe pour iPhone permettant de regarder ses applications iPhone sur son téléviseur. [...]

  14. Aral Balkan

    @momo: I completely agree. I can’t believe that I’ve now spent longer on trying to record a high-quality demo video of my app than I did in coding the major functionality in it.

    Enabling universal TV Out for iPhones makes makes perfect sense for apple as higher quality demo videos will translate to more sales and thus a higher income for Apple itself from its percentage of those sales.

  15. Rob

    Aral, have you tried recording the video out of the app?

    By the way, contrary to what I wrote above, this code DOES work with OpenGL. I have demoed games written with Unity 3D and Cocos2D using this. If you use a 3GS you can set the TVOut framerate to over 20 fps and it’s very acceptable.

  16. Matt Radford

    Is there a way of using this code to provide a better version of the jailbreak app TV-Out (or similar)?

    I’ve been trying to record app demos by using TV-Out, output to my Macbook, then using a screen recorder to capture this. But it’s not great, especially with high FPS games.

  17. Dan F

    Many thanks for sharing this. It worked on the first try in my app. Excellent work!

  18. Christian

    Hi Rob and “The Evil Boss”,
    thx for sharing this code. Really amazing…

    The only Problem i am struggling with, is the 16 bit color output of my iphone 3g. It looks horrible :( . The output of the 3GS seem to be 24/32 bit. Did someone have the same problem.

  19. TouchCentric » iPhone App Video Mirroring in Three Easy Steps

    [...] in Cocoa and I was wondering if I cout get some help or a brief tutorial on implementing the UIApplication+TVOut.m in a small project and I am trying to build please any and all help would greatly be [...]

  20. Eric

    This is great! Thanks for distilling this down to such a simple process.

    It looks like this still works for iPhone under SDK 3.2 … but, alas, it doesn’t seem to work for iPad under SDK 3.2.

    Does anyone know why? Or even have suggestions on how one (I) might find out?

    Thanks.
    -Eric

  21. TouchCentric » iPhone App Video Mirroring for iOS 4

    [...] Project the video of your iPhone app to thousands of adoring fans! This is an iOS 4.0 rewrite of the TVOut code described here: http://www.touchcentric.com/blog/archives/3. [...]

Leave a Reply

Your comment