2012-09-29 12 views
5

Tôi đang gặp phải tình huống lạ với trình phát video của mình, mã cốt lõi không thay đổi nhiều so với những gì đã làm trong một ứng dụng trước đó mà tôi đã tạo. Đây là vấn đề: Tôi đang chèn một "_loadingLayer" (một CATextLayer cho biết video đang tải), và sau đó quan sát thuộc tính trạng thái currentItem của AVPlayer để tìm ra khi nào xóa "_loadingLayer" và thay thế nó bằng "_playerLayer" thực tế của tôi . Đây là mã KVO của tôi cho rằng:AV Foundation: Sự khác biệt giữa currentItem đã sẵn sàng để chơi và - [AVPlayer readyForDisplay] thuộc tính?

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 

if ((object == _playerLayer) && (_playerLayer.player.currentItem.status == AVPlayerItemStatusReadyToPlay)) { 

    [CATransaction setAnimationDuration:1.8]; 

    _loadingLayer.opaque = NO; 

    if (_playerLayer.readyForDisplay) { 

     NSLog(@"Should be ready now."); 

    } 

    [self addPlayerLayerToLayerTree]; 

} 

} 

Vấn đề của tôi là video đang bắt đầu nhưng chỉ âm thanh đang phát - lớp màu đen. Khi tôi chèn câu lệnh NSLog ở trên, tôi đã tìm ra lý do: Rõ ràng mặc dù trạng thái của currentItem là "AVPlayerItemStatusReadyToPlay", lớp người chơi không thực sự readyForDisplay. Điều này không có ý nghĩa với tôi - nó có vẻ phản trực giác. Ai đó có thể xin vui lòng cho tôi một số hướng dẫn về điều này?

Tôi đã có thể xác minh rằng _playerLayer đang được thêm vào cây lớp bằng cách đặt màu nền thành màu đỏ.

Một điều kỳ lạ khác mà tôi nghĩ rằng có thể liên quan .... Tôi đã nhìn thấy những tin nhắn trong trình gỡ lỗi giao diện điều khiển:

PSsetwindowlevel, thiết lập lỗi mức cửa sổ (1000) CGSSetIgnoresCycle: Lỗi 1000 thiết lập hoặc xóa các thẻ cửa sổ

Xin cảm ơn trước. Đây là một tiền đồn từ Diễn đàn Apple Dev.

Trả lời

3

Chúng tôi đã gặp sự cố tương tự và theo dõi nó theo những gì tôi tin là lỗi trong iOS 5.1 (và có thể là các phiên bản cũ hơn). Nó được sửa trong iOS 6.0. Vì tôi không thể tìm ra giải pháp cho bất cứ nơi nào, tôi viết một bản viết dài cho những người trong tương lai có vấn đề này.

Nếu AVPlayerItem báo cáo trạng thái của AVPlayerStatusReadyToPlay trước khi AVPlayerLayer được lấy thì AVPlayer sẽ không bao giờ báo cáo rằng nó đã sẵn sàngĐối với hiển thị.

Vì vậy, khi bạn làm:

self.player = [AVPlayer playerWithPlayerItem:self.playerItem]; 

chắc chắn rằng nó được theo sau với:

self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; 

và rằng bạn không có nhiều nếu bất kỳ mã trong giữa hai người.

Tôi đã xây dựng một giàn khoan thử nghiệm để làm cho nó hoạt động 100% thời gian hoặc không đạt 100% thời gian. Lưu ý rằng nó có thể khó khăn để xem những gì đang xảy ra trong ứng dụng thực tế của bạn vì bạn sẽ có thời gian tải khác nhau trên video và điều đó sẽ ảnh hưởng đến tốc độ playerItem báo cáo AVPlayerStatusReadyToPlay.

Nếu bạn muốn thử nghiệm trong ứng dụng của mình, hãy đặt điều này vào chế độ xem đơn giản. Phần bên dưới sẽ không hoạt động (nghĩa là bạn sẽ nghe thấy âm thanh nhưng không thấy video) trên iOS 5.1. Thay vào đó, nếu bạn chuyển loadPlayerLayer thành được gọi ở cuối loadPlayer, nó sẽ luôn hoạt động.

Tiếp theo cho người đọc trong tương lai: Một vài sự kiện của người chơi có thể chuyển lên thứ tự này và khiến bạn nghĩ rằng nó hoạt động. Họ là những cô nàng tóc đỏ mặc dù họ vô tình đảo ngược thứ tự tải sao cho playerLayer được lấy trước AVStatusReadyToPlay. Các sự kiện là: tìm kiếm video, chuyển tới màn hình chính và sau đó kích hoạt lại ứng dụng, trình phát chuyển sang một đoạn video/âm thanh khác bên trong video HLS. Những hành động này kích hoạt AVStatusReadyToPlay một lần nữa và do đó làm cho playerLayer xảy ra trước khi AVStatusReadyToPlay.

Đây là khai thác thử nghiệm có sử dụng thử nghiệm HLS video của Apple:

-(void)loadPlayer 
{ 
    NSLog(@"loadPlayer invoked"); 

    NSURL *url = [NSURL URLWithString:@"https://devimages.apple.com.edgekey.net/resources/http-streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8"]; 
    self.playerItem = [AVPlayerItem playerItemWithURL:url]; 
    [self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:&kPlayerContext]; 
    self.player = [AVPlayer playerWithPlayerItem:self.playerItem]; 

} 

-(void)loadPlayerLayer 
{ 
    NSLog(@"starting player layer"); 
    self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; 
    [self.playerLayer addObserver:self forKeyPath:@"readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:&kPlayerLayerContext]; 
    [self.playerLayer setFrame:[[self view] bounds]]; 
    [[[self view] layer] addSublayer:self.playerLayer]; 
} 

-(void)observeValueForKeyPath:(NSString*)path ofObject:(id)object change:(NSDictionary*)change context:(void*) context 
{ 
    if(context == &kPlayerContext){ 
    if([self.player status] == AVPlayerStatusReadyToPlay){ 
     NSLog(@"Player is ready to play"); 
     //Robert: Never works if after AVPlayerItem reports AVPlayerStatusReadyToPlay 
     if(!self.startedPlayerLayer){ 
     self.startedPlayerLayer = YES; 
     [self loadPlayerLayer]; 
     } 
    } 
    } 

    if(context == &kPlayerLayerContext){ 
    if([self.playerLayer isReadyForDisplay] == YES){ 
     NSLog(@"PlayerLayer says it's ready to display now"); 
     [self playTheVideoIfReady]; 
    } 
    } 
} 
Các vấn đề liên quan