ArDrone SDK 1.8 added
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / ControlEngine / iPhone / Classes / Hide / TVOut.m
diff --git a/mardrone/ARDrone_SDK_Version_1_8_20110726/ControlEngine/iPhone/Classes/Hide/TVOut.m b/mardrone/ARDrone_SDK_Version_1_8_20110726/ControlEngine/iPhone/Classes/Hide/TVOut.m
new file mode 100644 (file)
index 0000000..b9bdd83
--- /dev/null
@@ -0,0 +1,244 @@
+//
+//  TVOut.m
+//  ARDroneEngine
+//
+//  Created by Frédéric D'HAEYER on 22/12/09.
+//  Copyright 2009 Parrot. All rights reserved.
+//
+#import "TVOut.h"
+
+#ifdef ENABLE_AUTO_TVOUT
+#import <QuartzCore/QuartzCore.h>
+#import <CoreGraphics/CoreGraphics.h>
+
+NSString * const UIApplicationDidSetupScreenMirroringNotification = @"UIApplicationDidSetupScreenMirroringNotification";
+NSString * const UIApplicationDidDisableScreenMirroringNotification = @"UIApplicationDidDisableScreenMirroringNotification";
+
+// Assuming CA loops at 60.0 fps (which is true on iPhone OS 3 : iPhone, iPad...)
+#define CORE_ANIMATION_MAX_FRAMES_PER_SECOND (60)
+
+CGImageRef UIGetScreenImage(); // Not so private API anymore
+
+static CFTimeInterval startTime = 0;
+static NSUInteger frames = 0;
+
+@interface TVOut (ScreenMirroringPrivate)
+
+- (void) setupMirroringForScreen:(UIScreen *)anExternalScreen;
+- (void) disableMirroringOnCurrentScreen;
+- (void) updateMirroredScreenOnDisplayLink;
+
+@end
+
+@implementation TVOut
+
+static double targetFramesPerSecond = 10.0;
+static CADisplayLink *displayLink = nil;
+static UIScreen *mirroredScreen = nil;
+static UIWindow *mirroredScreenWindow = nil;
+static UIImageView *mirroredImageView = nil;
+
+- (BOOL) isScreenMirroringActive
+{
+       return (displayLink && !displayLink.paused);
+}
+
+- (UIScreen *) currentMirroringScreen
+{
+       return mirroredScreen;
+}
+
+- (void) setupScreenMirroring
+{
+       [self setupScreenMirroringWithFramesPerSecond:targetFramesPerSecond];
+}
+
+- (void) setupScreenMirroringWithFramesPerSecond:(double)fps
+{
+       // Set the desired frame rate
+       targetFramesPerSecond = fps;
+       
+       // Register for screen notifications
+       NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+       [center addObserver:self selector:@selector(screenDidConnect:) name:UIScreenDidConnectNotification object:nil]; 
+       [center addObserver:self selector:@selector(screenDidDisconnect:) name:UIScreenDidDisconnectNotification object:nil]; 
+       [center addObserver:self selector:@selector(screenModeDidChange:) name:UIScreenModeDidChangeNotification object:nil]; 
+       
+       // Register for interface orientation changes (so we don't need to query on every frame refresh)
+       [center addObserver:self selector:@selector(interfaceOrientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
+       
+       // Setup screen mirroring for an existing screen
+       NSArray *connectedScreens = [UIScreen screens];
+       if ([connectedScreens count] > 1) {
+               UIScreen *mainScreen = [UIScreen mainScreen];
+               for (UIScreen *aScreen in connectedScreens) {
+                       if (aScreen != mainScreen) {
+                               // We've found an external screen !
+                               [self setupMirroringForScreen:aScreen];
+                               break;
+                       }
+               }
+       }
+}
+
+- (void) disableScreenMirroring
+{
+       // Unregister from screen notifications
+       NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+       [center removeObserver:self name:UIScreenDidConnectNotification object:nil];
+       [center removeObserver:self name:UIScreenDidDisconnectNotification object:nil];
+       [center removeObserver:self name:UIScreenModeDidChangeNotification object:nil];
+       
+       // Device orientation
+       [center removeObserver:self name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
+       
+       // Remove mirroring
+       [self disableMirroringOnCurrentScreen];
+}
+
+#pragma mark -
+#pragma mark UIScreen notifications
+
+- (void) screenDidConnect:(NSNotification *)aNotification
+{
+       NSLog(@"A new screen got connected: %@", [aNotification object]);
+       [self setupMirroringForScreen:[aNotification object]];
+}
+
+- (void) screenDidDisconnect:(NSNotification *)aNotification
+{
+       NSLog(@"A screen got disconnected: %@", [aNotification object]);
+       [self disableMirroringOnCurrentScreen];
+}
+
+- (void) screenModeDidChange:(NSNotification *)aNotification
+{
+       UIScreen *someScreen = [aNotification object];
+       NSLog(@"The screen mode for a screen did change: %@", [someScreen currentMode]);
+       
+       // Disable, then reenable with new config
+       [self disableMirroringOnCurrentScreen];
+       [self setupMirroringForScreen:[aNotification object]];
+}
+
+#pragma mark -
+#pragma mark Interface orientation changes notification
+
+- (void) updateMirroredWindowTransformForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+       // Grab the secondary window layer
+       CALayer *mirrorLayer = mirroredScreenWindow.layer;
+       
+       // Rotate the screenshot to match interface orientation
+       switch (interfaceOrientation) {
+               case UIInterfaceOrientationPortrait:
+                       mirrorLayer.transform = CATransform3DIdentity;
+                       break;
+               case UIInterfaceOrientationLandscapeLeft:
+                       mirrorLayer.transform = CATransform3DMakeRotation(M_PI / 2, 0.0f, 0.0f, 1.0f);
+                       break;
+               case UIInterfaceOrientationLandscapeRight:
+                       mirrorLayer.transform = CATransform3DMakeRotation(-(M_PI / 2), 0.0f, 0.0f, 1.0f);
+                       break;
+               case UIInterfaceOrientationPortraitUpsideDown:
+                       mirrorLayer.transform = CATransform3DMakeRotation(M_PI, 0.0f, 0.0f, 1.0f);
+                       break;
+               default:
+                       break;
+       }
+}
+
+- (void) interfaceOrientationWillChange:(NSNotification *)aNotification
+{
+       NSDictionary *userInfo = [aNotification userInfo];
+       UIInterfaceOrientation newInterfaceOrientation = (UIInterfaceOrientation) [[userInfo objectForKey:UIApplicationStatusBarOrientationUserInfoKey] unsignedIntegerValue];
+       [self updateMirroredWindowTransformForInterfaceOrientation:newInterfaceOrientation];
+}
+
+#pragma mark -
+#pragma mark Screen mirroring
+
+- (void) setupMirroringForScreen:(UIScreen *)anExternalScreen
+{       
+       // Reset timer
+       startTime = CFAbsoluteTimeGetCurrent();
+       frames = 0;
+       
+       // Set the new screen to mirror
+       BOOL done = NO;
+       UIScreenMode *mainScreenMode = [UIScreen mainScreen].currentMode;
+       for (UIScreenMode *externalScreenMode in anExternalScreen.availableModes) {
+               if (CGSizeEqualToSize(externalScreenMode.size, mainScreenMode.size)) {
+                       // Select a screen that matches the main screen
+                       anExternalScreen.currentMode = externalScreenMode;
+                       done = YES;
+                       break;
+               }
+       }
+       
+       if (!done && [anExternalScreen.availableModes count]) {
+               anExternalScreen.currentMode = [anExternalScreen.availableModes objectAtIndex:0];
+       }
+       
+       [mirroredScreen release];
+       mirroredScreen = [anExternalScreen retain];
+       
+       // Setup window in external screen      
+       UIWindow *newWindow = [[UIWindow alloc] initWithFrame:mirroredScreen.bounds];
+       newWindow.opaque = YES;
+       newWindow.hidden = NO;
+       newWindow.backgroundColor = [UIColor blackColor];
+       newWindow.layer.contentsGravity = kCAGravityResizeAspect;
+       [mirroredScreenWindow release];
+       mirroredScreenWindow = [newWindow retain];
+       mirroredScreenWindow.screen = mirroredScreen;
+       [newWindow release];
+       
+       // Apply transform on mirrored window to match device's interface orientation
+       [self updateMirroredWindowTransformForInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
+       
+       // Setup periodic callbacks
+       [displayLink invalidate];
+       [displayLink release], displayLink = nil;
+       
+       // Setup display link sync
+       displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(updateMirroredScreenOnDisplayLink)] retain];
+       [displayLink setFrameInterval:(targetFramesPerSecond >= CORE_ANIMATION_MAX_FRAMES_PER_SECOND) ? 1 : (CORE_ANIMATION_MAX_FRAMES_PER_SECOND / targetFramesPerSecond)];
+       
+       // We MUST add ourselves in the commons run loop in order to mirror during UITrackingRunLoopMode.
+       // Otherwise, the display won't be updated while fingering are touching the screen.
+       // This has a major impact on performance though...
+       [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
+       
+       // Post notification advertisting that we're setting up mirroring for the external screen
+       [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidSetupScreenMirroringNotification object:anExternalScreen];
+}
+
+- (void) disableMirroringOnCurrentScreen
+{
+       // Post notification advertisting that we're tearing down mirroring
+       [[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidDisableScreenMirroringNotification object:mirroredScreen];
+       
+       [displayLink invalidate];
+       [displayLink release], displayLink = nil;
+       
+       [mirroredScreen release], mirroredScreen = nil;
+       [mirroredScreenWindow release], mirroredScreenWindow = nil;
+       [mirroredImageView release], mirroredImageView = nil;
+}
+
+- (void) updateMirroredScreenOnDisplayLink
+{
+       // Get a screenshot of the main window
+       CGImageRef mainWindowScreenshot = UIGetScreenImage();
+       if (mainWindowScreenshot) {
+               // Copy to secondary screen
+               mirroredScreenWindow.layer.contents = (id) mainWindowScreenshot;
+               // Clean up as UIGetScreenImage does NOT respect retain / release semantics
+               CFRelease(mainWindowScreenshot); 
+       }
+}
+
+@end
+
+#endif // ENABLE_AUTO_TVOUT
\ No newline at end of file