MacGui: fallback to QTKit if a preview is not playable with AVFoundation.
authorDamiano Galassi <damiog@gmail.com>
Thu, 19 May 2016 11:44:52 +0000 (13:44 +0200)
committerDamiano Galassi <damiog@gmail.com>
Thu, 19 May 2016 11:44:52 +0000 (13:44 +0200)
macosx/HBAVPlayer.m
macosx/HBPlayerHUDController.m
macosx/HBPreviewController.m
macosx/HBQTKitPlayer.m

index 748aa39f1b60cacf3dba8061ebf4f17d23b883a0..892cf17f92e780daf69876c684791430cdea628d 100644 (file)
@@ -40,7 +40,8 @@ typedef void (^HBPlayableObverser)(void);
 @property (nonatomic, strong) NSMutableSet<HBAVPlayerRateObserver *> *rateObservers;
 @property (nonatomic, strong) NSMutableSet<HBPlayableObverser> *playableObservers;
 
-@property (nonatomic, readwrite) BOOL playable;
+@property (nonatomic, readwrite, getter=isPlayable) BOOL playable;
+@property (nonatomic, readwrite, getter=isLoaded) BOOL loaded;
 
 @end
 
@@ -53,20 +54,9 @@ typedef void (^HBPlayableObverser)(void);
     if (self)
     {
         _movie = [AVAsset assetWithURL:url];;
-
-        if (!_movie)
-        {
-            return nil;
-        }
-
         _player = [[AVPlayer alloc] init];
         _layer = [CALayer layer];
 
-        if (!_layer || !_player)
-        {
-            return nil;
-        }
-
         _rateObservers = [NSMutableSet set];
         _playableObservers = [NSMutableSet set];
 
@@ -80,6 +70,7 @@ typedef void (^HBPlayableObverser)(void);
             // Because we want to access our AVPlayer in our ensuing set-up, we must dispatch our handler to the main queue.
             dispatch_async(dispatch_get_main_queue(), ^(void) {
                 [self _setUpPlaybackOfAsset:_movie withKeys:assetKeysToLoadAndTest];
+                self.loaded = YES;
             });
 
         }];
@@ -128,9 +119,9 @@ typedef void (^HBPlayableObverser)(void);
     }
 }
 
-- (void)setPlayable:(BOOL)playable
+- (void)setLoaded:(BOOL)loaded
 {
-    _playable = playable;
+    _loaded = loaded;
 
     for (HBPlayableObverser block in self.playableObservers)
     {
@@ -290,7 +281,7 @@ typedef void (^HBPlayableObverser)(void);
 
 - (void)loadPlayableValueAsynchronouslyWithCompletionHandler:(nullable void (^)(void))handler;
 {
-    if (self.playable)
+    if (self.isLoaded)
     {
         handler();
     }
index ebafc95c1388317ff378dd65ef4a7986ca6539a6..3524f79e3137f8b47528d42eaea5d993f56e5ea4 100644 (file)
@@ -95,7 +95,9 @@
         [self.slider setMinValue:0.0];
         [self.slider setMaxValue:self.player.duration];
         [self.slider setDoubleValue:0.0];
-        
+
+        self.player.volume = self.volumeSlider.floatValue;
+
         [self.player play];
     }
 }
index 1db48cdcd5e4f79bb86cbd749190941847d9eefa..9c8903b7e7424deefc9574a9ae2c077c56a33805 100644 (file)
 
         // adjust the preview slider length
         self.pictureHUD.pictureCount = generator.imagesCount;
-        [self switchStateToHUD:self.pictureHUD];
     }
     else
     {
         self.previewView.image = nil;
-        self.currentHUD.view.hidden = YES;
         self.window.title = NSLocalizedString(@"Preview", nil);
     }
+    [self switchStateToHUD:self.pictureHUD];
 }
 
 - (void)reloadPreviews
     for (NSViewController *controller in huds) {
         controller.view.hidden = YES;
     }
-    hud.view.hidden = NO;
-    hud.view.layer.opacity = 1.0;
+    if (self.generator)
+    {
+        hud.view.hidden = NO;
+        hud.view.layer.opacity = 1.0;
+    };
 
     [self.window makeFirstResponder:hud.view];
     [self startHudTimer];
     }
 }
 
-- (void)setUpPlaybackOfURL:(NSURL *)fileURL;
+- (void)setUpPlaybackOfURL:(NSURL *)fileURL playerClass:(Class)class;
 {
-    if (self.player.isPlayable && self.currentHUD == self.encodingHUD)
+    NSArray<Class> *availablePlayerClasses = @[[HBAVPlayer class], [HBQTKitPlayer class]];
+
+    self.player = [[class alloc] initWithURL:fileURL];
+
+    if (self.player)
     {
-        [self switchStateToHUD:self.playerHUD];
+        [self.player loadPlayableValueAsynchronouslyWithCompletionHandler:^{
+
+            dispatch_async(dispatch_get_main_queue(), ^{
+                if (self.player.isPlayable && self.currentHUD == self.encodingHUD)
+                {
+                    [self switchStateToHUD:self.playerHUD];
+                }
+                else
+                {
+                    // Try to open the preview with the next player class.
+                    NSUInteger idx = [availablePlayerClasses indexOfObject:class];
+                    if (idx != NSNotFound && (idx + 1) < availablePlayerClasses.count)
+                    {
+                        Class nextPlayer = availablePlayerClasses[idx + 1];
+                        [self setUpPlaybackOfURL:fileURL playerClass:nextPlayer];
+                    }
+                    else
+                    {
+                        [self showAlert:fileURL];
+                        [self switchStateToHUD:self.pictureHUD];
+                    }
+                }
+            });
+
+        }];
     }
     else
     {
 
 - (void)didCreateMovieAtURL:(NSURL *)fileURL
 {
-    if (fileURL)
-    {
-        self.player = [[HBAVPlayer alloc] initWithURL:fileURL];
-
-               if (self.player)
-        {
-            [self.player loadPlayableValueAsynchronouslyWithCompletionHandler:^{
-
-                dispatch_async(dispatch_get_main_queue(), ^{
-                    [self setUpPlaybackOfURL:fileURL];
-                });
-
-            }];
-               }
-        else
-        {
-            [self showAlert:fileURL];
-            [self switchStateToHUD:self.pictureHUD];
-        }
-    }
+    [self setUpPlaybackOfURL:fileURL playerClass:[HBAVPlayer class]];
 }
 
 #pragma mark - Player mode
index b0b608e3ab1feeecd8dfd18c19d6d4382c2c55d4..e44413f55e061fe9d69a52b255b9125911894ac4 100644 (file)
@@ -57,6 +57,7 @@ typedef void (^HBPlayableObverser)(void);
 @property (nonatomic, strong) NSTimer *timer;
 
 @property (nonatomic, readwrite, getter=isPlayable) BOOL playable;
+@property (nonatomic, readwrite, getter=isLoaded) BOOL loaded;
 
 @property (nonatomic, strong) NSMutableSet<HBQTKitPlayerPeriodicObserver *> *periodicObservers;
 @property (nonatomic, strong) NSMutableSet<HBQTKitPlayerRateObserver *> *rateObservers;
@@ -78,38 +79,41 @@ typedef void (^HBPlayableObverser)(void);
                                       QTMovieAskUnresolvedDataRefsAttribute: @NO,
                                       QTMovieOpenForPlaybackAttribute: @YES,
                                       QTMovieIsSteppableAttribute: @YES,
-                                      QTMovieOpenAsyncRequiredAttribute: @YES,
+                                      QTMovieOpenAsyncRequiredAttribute: @NO,
+                                      QTMovieOpenAsyncOKAttribute: @NO,
                                       QTMovieApertureModeAttribute: QTMovieApertureModeClean };
 
         _movie = [[QTMovie alloc] initWithAttributes:attributes error:&outError];
         
-        if (!_movie)
+        if (_movie)
         {
-            return nil;
-        }
-
-        _movie.delegate = self;
-
-        [[NSNotificationCenter defaultCenter] addObserver:self
-                                                 selector:@selector(_movieRateDidChange:)
-                                                     name:QTMovieRateDidChangeNotification
-                                                   object:_movie];
+            _movie.delegate = self;
 
-        [[NSNotificationCenter defaultCenter] addObserver:self
-                                                 selector:@selector(_loadStateChanged:)
-                                                     name:QTMovieLoadStateDidChangeNotification
-                                                   object:_movie];
+            [[NSNotificationCenter defaultCenter] addObserver:self
+                                                     selector:@selector(_movieRateDidChange:)
+                                                         name:QTMovieRateDidChangeNotification
+                                                       object:_movie];
 
-        _layer = [QTMovieLayer layerWithMovie:_movie];
-
-        if (!_layer)
-        {
-            return nil;
+            _layer = [QTMovieLayer layerWithMovie:_movie];
         }
 
         _periodicObservers = [NSMutableSet set];
         _rateObservers = [NSMutableSet set];
         _playableObservers = [NSMutableSet set];
+
+        // Can't open things async
+        // because of 23414 QTKit bugs.
+        if (_movie && _layer)
+        {
+            self.playable = YES;
+            [self _enableSubtitles];
+        }
+        else
+        {
+            self.playable = NO;
+        }
+
+        self.loaded = YES;
     }
 
     return self;
@@ -121,9 +125,9 @@ typedef void (^HBPlayableObverser)(void);
     [self _stopMovieTimer];
 }
 
-- (void)setPlayable:(BOOL)playable
+- (void)setLoaded:(BOOL)loaded
 {
-    _playable = playable;
+    _loaded = loaded;
 
     for (HBPlayableObverser block in self.playableObservers)
     {
@@ -132,17 +136,6 @@ typedef void (^HBPlayableObverser)(void);
     [self.playableObservers removeAllObjects];
 }
 
-- (void)_loadStateChanged:(NSNotification *)notification
-{
-    int loadState = [[self.movie attributeForKey:QTMovieLoadStateAttribute] intValue];
-
-    if (loadState >= QTMovieLoadStateLoaded)
-    {
-        [self _enableSubtitles];
-        self.playable = YES;
-    }
-}
-
 - (void)_movieRateDidChange:(NSNotification *)notification
 {
     for (HBQTKitPlayerRateObserver *observer in self.rateObservers)
@@ -325,7 +318,7 @@ typedef void (^HBPlayableObverser)(void);
 
 - (void)loadPlayableValueAsynchronouslyWithCompletionHandler:(nullable void (^)(void))handler;
 {
-    if (self.playable)
+    if (self.isLoaded)
     {
         handler();
     }