2012-06-05 5 views
3

Каков самый простой способ воспроизведения видео с помощью Objective-C в Mac OS X 10.7 (Lion)? И если я хочу поддерживать OS X 10.6 (Snow Leopard) тоже?Воспроизвести видео в Mac OS X 10.7

Я заметил, что iOS AV Foundation был представлен OS X 10.7. К сожалению, документация, похоже, написана для iOS, и я счел ее запутанной.

+0

Когда Apple делает рекомендации, они почти всегда рекомендуют новейшую и shiniest API, особенно, когда это делает его легко портировать код между OS X и прошивкой , Это то, о чем вы просите, «рекомендуется»? Или вы спрашиваете личный опыт других разработчиков? Потому что в этом случае вы получите совсем другой ответ (возможно, с участием QTKit и/или CoreAnimation, но это зависит именно от того, что вы хотите сделать). – abarnert

+0

Персональный опыт другого разработчика. Я перефразую до «простейшего». – hpique

ответ

2

«Простейший» зависит от того, что вы пытаетесь сделать. Если вам требуется больше контроля (например, рендеринг фильма как текстуры OpenGL) или меньше (например, полностью независимое окно, которое вы можете просто всплывать и игнорировать), могут быть разные ответы.

Но для большинства случаев использования, если вы хотите поддержку 10.6+, самым простым способом показать фильм является QTKit. Хорошую отправную точку см. В статье «Использование QTKit для воспроизведения мультимедиа» в документации Xcode.

5

Вот подкласс NSView, который воспроизводит видео с использованием URL-адреса, используя AV Foundation (таким образом, Mac OS X 10.7 вверх). На основе кода примера AVSimplePlayer.

Заголовок:

@interface RMVideoView : NSView 

@property (nonatomic, readonly, strong) AVPlayer* player; 
@property (nonatomic, readonly, strong) AVPlayerLayer* playerLayer; 
@property (nonatomic, retain) NSURL* videoURL; 

- (void) play; 

@end 

Реализация:

static void *RMVideoViewPlayerLayerReadyForDisplay = &RMVideoViewPlayerLayerReadyForDisplay; 
static void *RMVideoViewPlayerItemStatusContext = &RMVideoViewPlayerItemStatusContext; 

@interface RMVideoView() 

- (void)onError:(NSError*)error; 
- (void)onReadyToPlay; 
- (void)setUpPlaybackOfAsset:(AVAsset *)asset withKeys:(NSArray *)keys; 

@end 

@implementation RMVideoView 

@synthesize player = _player; 
@synthesize playerLayer = _playerLayer; 
@synthesize videoURL = _videoURL; 

- (id)initWithFrame:(NSRect)frame { 
    self = [super initWithFrame:frame]; 
    if (self) { 
     self.wantsLayer = YES; 
     _player = [[AVPlayer alloc] init]; 
     [self addObserver:self forKeyPath:@"player.currentItem.status" options:NSKeyValueObservingOptionNew context:RMVideoViewPlayerItemStatusContext]; 
    } 

    return self; 
} 

- (void) dealloc { 
    [self.player pause]; 
    [self removeObserver:self forKeyPath:@"player.currentItem.status"]; 
    [self removeObserver:self forKeyPath:@"playerLayer.readyForDisplay"]; 
    [_player release]; 
    [_playerLayer release]; 
    [_videoURL release]; 
    [super dealloc]; 
} 

- (void) setVideoURL:(NSURL *)videoURL { 
    _videoURL = videoURL; 

    [self.player pause]; 
    [self.playerLayer removeFromSuperlayer]; 

    AVURLAsset *asset = [AVAsset assetWithURL:self.videoURL]; 
    NSArray *assetKeysToLoadAndTest = [NSArray arrayWithObjects:@"playable", @"hasProtectedContent", @"tracks", @"duration", nil]; 
    [asset loadValuesAsynchronouslyForKeys:assetKeysToLoadAndTest completionHandler:^(void) { 
     dispatch_async(dispatch_get_main_queue(), ^(void) { 
      [self setUpPlaybackOfAsset:asset withKeys:assetKeysToLoadAndTest]; 
     }); 
    }]; 
} 

#pragma mark - KVO 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
    if (context == RMVideoViewPlayerItemStatusContext) { 
     AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue]; 
     switch (status) { 
      case AVPlayerItemStatusUnknown: 
       break; 
      case AVPlayerItemStatusReadyToPlay: 
       [self onReadyToPlay]; 
       break; 
      case AVPlayerItemStatusFailed: 
       [self onError:nil]; 
       break; 
     } 
    } else if (context == RMVideoViewPlayerLayerReadyForDisplay) { 
     if ([[change objectForKey:NSKeyValueChangeNewKey] boolValue]) { 
      self.playerLayer.hidden = NO; 
     } 
    } else { 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
    } 
} 


#pragma mark - Private 

- (void)onError:(NSError*)error { 
    // Notify delegate 
} 

- (void)onReadyToPlay { 
    // Notify delegate 
} 

- (void)setUpPlaybackOfAsset:(AVAsset *)asset withKeys:(NSArray *)keys { 
    for (NSString *key in keys) { 
     NSError *error = nil; 
     if ([asset statusOfValueForKey:key error:&error] == AVKeyValueStatusFailed) { 
      [self onError:error]; 
      return; 
     } 
    } 

    if (!asset.isPlayable || asset.hasProtectedContent) { 
     [self onError:nil]; 
     return; 
    } 

    if ([[asset tracksWithMediaType:AVMediaTypeVideo] count] != 0) { // Asset has video tracks 
     _playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; 
     self.playerLayer.frame = self.layer.bounds; 
     self.playerLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; 
     self.playerLayer.hidden = YES; 
     [self.layer addSublayer:self.playerLayer]; 
     [self addObserver:self forKeyPath:@"playerLayer.readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:RMVideoViewPlayerLayerReadyForDisplay]; 
    } 

    // Create a new AVPlayerItem and make it our player's current item. 
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset]; 
    [self.player replaceCurrentItemWithPlayerItem:playerItem]; 
} 

#pragma mark - Public 

- (void) play { 
    [self.player play]; 
} 

@end 
+0

Поскольку OP хочет поддерживать 10.6, это не очень полезно. Но он также просил не путать с AVFoundation. – abarnert

+0

@abarnert Я ОП. Я хотел дополнить свой ответ способом AV Foundation. – hpique

+0

Ах, в этом случае вы, вероятно, знаете, что OP хочет немного лучше, чем я. :) – abarnert

Смежные вопросы