2

我有一个 iPad 应用程序使用变体播放列表播放 http 视频流,它具有针对不同带宽的不同比特率的多个流。其中之一是最低带宽的仅音频流。该应用程序使用AVPlayer播放视频。出于某种原因,我不能使用 MPMoviePlayerViewController。

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

标准 iPad 视频播放器 - 仅播放音频流

有什么方法可以检测播放器何时切换到不同的流?或者检测流是否是纯音频的?

4

3 回答 3

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 非常简单,应该包含您的实现。
于 2013-12-24T11:49:13.653 回答
2

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

[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 协议AVPlayerItem

于 2011-05-13T02:57:24.317 回答
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

于 2015-02-10T09:57:46.310 回答