2011-05-04 96 views
2

我有一个使用变体播放列表播放http视频流的iPad应用程序,它具有不同带宽的不同比特率的多个流。其中之一是音频只有最低带宽的流。该应用使用AVPlayer播放视频。出于某种原因,我无法使用MPMoviePlayerViewController。iPhone HTTP视频流:播放纯音频流时如何显示静止图像

我的问题是当视频播放器播放音频流视频显示黑屏时,音频仍在播放。我认为这对用户来说很糟糕,他们不知道发生了什么。我想显示静态图像来代替视频播放器。这样

Standard iPad Video Player - Playing Audio Stream only

有没有什么办法可以检测当玩家切换到不同的流?或者检测流是否仅音频?

+0

有了。 “出于某种原因,我不能使用MPMoviePlayerViewController”,你的意思是有原因的你不不知道或你知道并且与之共处的理由? – 2011-05-04 17:19:14

+0

那么主要原因是我必须建立自定义视频播放器。 – TuanCM 2011-05-06 10:35:07

回答

2

您可以为AVPlayerItem中的tracks属性设置观察者。

[yourPlayer.currentItem addObserver:self forKeyPath:@"tracks" options:0 context:nil]; 

比你需要实现方法都会被调用时,轨道将被改变

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if ([keyPath isEqual:@"tracks"]) 
    { 
     for (AVPlayerItemTrack* track in [[yourPlayer.currentItem] tracks]) 
     { 
      if ([track.assetTrack.mediaType isEqual:AVMediaTypeAudio]) 
      { 
       // Audio track available 
      } 
      if ([track.assetTrack.mediaType isEqual:AVMediaTypeVideo]) 
      { 
       // Video track available 
      } 
     } 
    } 
} 

有用于调整一些空间,看看NSKeyValueObserving ProtocolAVPlayerItem

+0

这实际上很聪明。让我试试这个。万分感谢。 – TuanCM 2011-05-18 13:54:01

3

由于时间我遇到过这个问题,以前的回答不完整(不包括直播案例) - 这里是我的改进之处:

if ([keyPath isEqual:@"tracks"]) 
    { 
     BOOL hasVideoTrack = NO; 
     for (AVPlayerItemTrack* track in [[yourPlayer.currentItem] tracks]) 
     {     
      if ([track.assetTrack.mediaType isEqual:AVMediaTypeVideo]) 
      { 
       hasVideoTrack = YES; 
       break; 
      } 
     } 
     if (hasVideoTrack) 
     { 
      // Remove audio only view 
     } else { 
      // Show audio only view 
     } 
    } 

请注意 - 但这只会让您显示本地音频屏幕。 当播放实时流 - 艺术品的音频仅从何而来流,所以我的代码更趋向这样的:

if ([keyPath isEqualToString:@"timedMetadata"] == YES){ 
for (AVMetadataItem *metadata in self.player.currentItem.timedMetadata) { 
    if ([[metadata commonKey] isEqualToString:@"artwork"]) { 
     UIImage *overlayImage = [UIImage imageWithData:metadata.dataValue]; 
     UIImageView *overlayImageView = [[UIImageView alloc] initWithImage:overlayImage]; 
     overlayImageView.contentMode = UIViewContentModeScaleAspectFit; 

     // If an audio only slide is already there, make it disappear. 
     [self hideAudioOnlySlide]; 

     self.audioOnlyView = overlayImageView; 
     [self showAudioOnlySlide]; 
     self.audioOnlyView.size = _playerView.size; 
     break; 
    } 
} 


}else if ([keyPath isEqualToString:@"tracks"] == YES){ 
    NSArray *tracks = self.player.currentItem.tracks;    
    if ([self.player.currentItem hasVideoTracks] == NO) { 
     // Check if there is timed metadata with artwork that indicates audio only is handled at the stream level. 
     BOOL hasAudioOnlyFromStream = NO; 
     for (AVMetadataItem *metadata in self.player.currentItem.timedMetadata) { 
      if ([[metadata commonKey] isEqualToString:@"artwork"]) { 
       hasAudioOnlyFromStream = YES; 
       break; 
      } 
     } 
     // If we don't have audio only slide from the stream - carry on to show audio only slide. 
     //Otherwise - this is handled by the timed metadata check for artwork. 
     if (hasAudioOnlyFromStream == NO) { 
      [self showAudioOnlySlide]; 
     } 
    } else { 
     [self hideAudioOnlySlide]; 
    } 
} 

添加观察代码:

[item addObserver:self forKeyPath:@"timedMetadata" options:0 context:NULL]; 
[item addObserver:self forKeyPath:@"tracks" options:0 context:NULL]; 

删除观察代码:

@try { 
    [item removeObserver:self forKeyPath:@"timedMetadata"]; 
    [item removeObserver:self forKeyPath:@"tracks"]; 
} 

hasVideoTracks代码(在类别上AVPlayerItem):

- (BOOL)hasVideoTracks{ 
    BOOL hasVideoTracks = NO; 
    for (AVPlayerItemTrack* track in [self tracks]){ 
     if ([track.assetTrack.mediaType isEqual:AVMediaTypeVideo]){ 
      hasVideoTracks = YES; 
      break; 
     } 
    } 

    return hasVideoTracks; 
} 

注:

  1. 切勿使用presentationSize,只能检测到音频 - 在iOS的7只移动音频当它不再成为CGSizeZero - 但给出了一些时髦的尺寸来代替。这不是一个可靠的方法。
  2. 显示/隐藏audioOnlySlide非常简单,应该包含您的实现。
+0

我试过你的代码,但我发现hasVideoTracks = Yes,即使当http实时流只播放音频(视频播放停滞) – karthik 2015-08-20 15:48:50

+0

有趣的是,什么操作系统是什么?我的代码是为7编写的,当然它的工作正常。也许他们再次搞砸了。 此外 - 你想尝试点播或直播?你是否确认你有一个正确编码的音频流? (有或没有幻灯片?) – 2015-08-21 21:17:03

+0

我在iOS 8.4中运行,我正在尝试实时流,可以告诉我如何检查编码音频只有流属性,并且我在这里创建了一个关于这个堆栈溢出的问题http://stackoverflow.com/q/32123030/1730345,可以帮助我解决这个问题。 – karthik 2015-08-23 01:43:11

1

掌握现代媒体播放(WWDC 2014):

AVPlayer and AVPlayerItem 
Deciding when to show audio-only UI 
// Inside -observeValueForKeyPath:ofObject:change:context: implementation... 
if (presentationSizeObservationContext == context) { 
    // Check if new presentation size is CGSizeZero. 
    CGSize size = change[NSKeyValueChangeNewKey].sizeValue; 
    if (CGSizeEqualToSize(size, CGSizeZero)) { 
     for (AVPlayerItemTrack *playerItemTrack in playerItem.tracks) { 
      AVAssetTrack *track = playerItemTrack.assetTrack; 
      if ([track hasMediaCharacteristic:AVMediaCharacteristicAudible]) { 
       // Show audio-only UI. 
      } 
     } 
    } 
} 

链接:https://developer.apple.com/videos/wwdc/2014/#503

+0

你在哪里定义if语句的上下文? – user2924482 2015-10-03 07:00:22