我有一个iPad应用程序使用变体播放列表播放http视频流,该播放列表具有针对不同带宽的不同比特率的多个流。其中一个是仅用于最低带宽的音频流。该应用使用 AVPlayer 播放视频。出于某种原因,我无法使用MPMoviePlayerViewController。
我遇到的问题是,当视频播放器播放仅音频流时,视频显示黑屏,音频仍在播放。我认为对用户来说很糟糕,他们不知道发生了什么。我想显示静止图像来代替视频播放器。像这样
当播放器切换到不同的流时,有什么办法可以检测到吗?或者检测流是否只是音频?
答案 0 :(得分: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 :(得分: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 Protocol和AVPlayerItem
答案 2 :(得分: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.
}
}
}
}