- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在使用 Apple 的文档演示。这是演示链接: AVPlayerDemo
我的应用程序在执行以下步骤后崩溃了:
1) 播放歌曲
2) 从搜索栏快进。
3)点击下一步,4) 从搜索栏快进。
这是我的崩溃日志:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'An instance of AVPlayer cannot remove a time observer that was added by a different instance of AVPlayer.'
下面是音乐播放器的代码:
- (NSTimeInterval) playableDuration
{
// use loadedTimeRanges to compute playableDuration.
AVPlayerItem * item = player.currentItem;
if (item.status == AVPlayerItemStatusReadyToPlay) {
NSArray * timeRangeArray = item.loadedTimeRanges;
CMTimeRange aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];
double startTime = CMTimeGetSeconds(aTimeRange.start);
double loadedDuration = CMTimeGetSeconds(aTimeRange.duration);
NSLog(@"get time range, its start is %f seconds, its duration is %f seconds.", startTime/60, loadedDuration/60);
return (NSTimeInterval)(startTime + loadedDuration);
}
else
{
return(CMTimeGetSeconds(kCMTimeInvalid));
}
}
-(NSTimeInterval)currentItemPlayableDuration{
// use loadedTimeRanges to compute playableDuration.
AVPlayerItem * item = player.currentItem;
if (item.status == AVPlayerItemStatusReadyToPlay) {
NSArray * timeRangeArray = item.loadedTimeRanges;
CMTime currentTime = player.currentTime;
__block CMTimeRange aTimeRange;
[timeRangeArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];
if(CMTimeRangeContainsTime(aTimeRange, currentTime))
*stop = YES;
}];
CMTime maxTime = CMTimeRangeGetEnd(aTimeRange);
return CMTimeGetSeconds(maxTime);
}
else
{
return(CMTimeGetSeconds(kCMTimeInvalid));
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(player!= nil)
{
[player.currentItem removeObserver:self forKeyPath:@"status"];
}
[player pause];
player = nil;
btnPlay.hidden=true;
btnPause.hidden=false;
selectedSongIndex = indexPath.row;
url = [[NSURL alloc] initWithString:[arrURL objectAtIndex:indexPath.row]];
[self setupAVPlayerForURL:url];
//[player play];
AVPlayerItem *item = player.currentItem;
[item addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil];
[player play];
//[tableView deselectRowAtIndexPath:indexPath animated:YES];
} #pragma mark - Player Methods
- (IBAction)btnBack_Click:(id)sender {
int index = selectedSongIndex;
if (index==0) {
if(player!= nil)
{
[player.currentItem removeObserver:self forKeyPath:@"status"];
}
[player pause];
player = nil;
selectedSongIndex = [arrURL count]-1;
url = [[NSURL alloc] initWithString:[arrURL objectAtIndex:selectedSongIndex]];
[self setupAVPlayerForURL:url];
AVPlayerItem *item = player.currentItem;
[item addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil];
[player play];
}
else if(index >= 0 && index < [arrURL count])
{
if(player!= nil)
{
[player.currentItem removeObserver:self forKeyPath:@"status"];
}
[player pause];
player = nil;
index = selectedSongIndex - 1;
selectedSongIndex = index;
url = [[NSURL alloc] initWithString:[arrURL objectAtIndex:index]];
[self setupAVPlayerForURL:url];
AVPlayerItem *item = player.currentItem;
[item addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil];
[player play];
}
}
- (IBAction)btnPlay_Click:(id)sender {
btnPlay.hidden=true;
btnPause.hidden=false;
//url = [[NSURL alloc] initWithString:[arrURL objectAtIndex:indexPath.row]];
if([strPlay isEqualToString:@"ViewWillAppear"] || [strPlay isEqualToString:@"Stop"])
{
[currentTimeSlider setValue:0.0];
lblStart.text = @"0:00";
[self setupAVPlayerForURL:url];
}
AVPlayerItem *item = player.currentItem;
[item addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil];
[player play];
}
- (IBAction)btnPause_Click:(id)sender {
btnPlay.hidden=false;
btnPause.hidden=true;
strPlay = @"Pause";
[player pause];
}
- (IBAction)btnStop_Click:(id)sender {
btnPlay.hidden=false;
btnPause.hidden=true;
strPlay = @"Stop";
//[player removeObserver:self forKeyPath:@"status"];
[player pause];
player = nil;
}
- (IBAction)btnNext_Click:(id)sender {
int index = selectedSongIndex;
if(selectedSongIndex == [arrURL count]-1)
{
if(player!= nil)
{
[player.currentItem removeObserver:self forKeyPath:@"status"];
}
[player pause];
player = nil;
AVPlayerItem *item = player.currentItem;
[item removeObserver:self forKeyPath:@"timedMetadata"];
selectedSongIndex=0;
url = [[NSURL alloc] initWithString:[arrURL objectAtIndex:0]];
[self setupAVPlayerForURL:url];
AVPlayerItem *item1 = player.currentItem;
[item1 addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil];
[player play];
}
else if(index < [arrURL count])
{
if(player!= nil)
{
[player.currentItem removeObserver:self forKeyPath:@"status"];
}
[player pause];
player = nil;
AVPlayerItem *item = player.currentItem;
[item removeObserver:self forKeyPath:@"timedMetadata"];
index = selectedSongIndex+1;
selectedSongIndex = index;
url = [[NSURL alloc] initWithString:[arrURL objectAtIndex:index]];
[self setupAVPlayerForURL:url];
AVPlayerItem *item1 = player.currentItem;
[item1 addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil];
[player play];
}
}
-(void) setupAVPlayerForURL: (NSURL*) url1 {
AVAsset *asset = [AVURLAsset URLAssetWithURL:url1 options:nil];
AVPlayerItem *anItem = [AVPlayerItem playerItemWithAsset:asset];
if(player!= nil)
{
[player.currentItem removeObserver:self forKeyPath:@"status"];
}
player = [AVPlayer playerWithPlayerItem:anItem];
[player.currentItem addObserver:self forKeyPath:@"status" options:0 context:nil];
[player play];
}
- (CMTime)playerItemDuration
{
AVPlayerItem *thePlayerItem = [player currentItem];
if (thePlayerItem.status == AVPlayerItemStatusReadyToPlay)
{
return([thePlayerItem duration]);
}
return(kCMTimeInvalid);
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([keyPath isEqualToString:@"timedMetadata"])
{
AVPlayerItem *item = (AVPlayerItem *)object;
NSLog(@"Item.timedMetadata: %@",item.timedMetadata);
NSLog(@"-- META DATA ---");
// AVPlayerItem *pItem = (AVPlayerItem *)object;
for (AVMetadataItem *metaItem in item.timedMetadata) {
NSLog(@"meta data = %@",[metaItem commonKey]);
NSString *key = [metaItem commonKey]; //key = publisher , key = title
NSString *value = [metaItem stringValue];
NSLog(@"key = %@, value = %@", key, value);
if([[metaItem commonKey] isEqualToString:@"title"])
{
self.lblTitle.text = [metaItem stringValue];
}
}
}
if (object == player.currentItem && [keyPath isEqualToString:@"status"]) {
if (player.status == AVPlayerStatusFailed) {
NSLog(@"AVPlayer Failed");
} else if (player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
NSLog(@"AVPlayer Ready to Play");
NSTimeInterval totalSeconds = CMTimeGetSeconds(player.currentItem.asset.duration);
int minutes = (int)totalSeconds / 60;
int seconds = (int)totalSeconds % 60;
NSString *minutes1;
NSString *seconds1;
if (minutes < 10) {
minutes1=[NSString stringWithFormat:@"%02d",minutes];
seconds1=[NSString stringWithFormat:@"%02d",seconds];
}
lblEnd.text = [NSString stringWithFormat:@"%@:%@",minutes1,seconds1];
NSLog(@"lblEnd Duration: %@",lblEnd.text);
double interval = .1f;
CMTime playerDuration = [self playerItemDuration]; // return player duration.
if (CMTIME_IS_INVALID(playerDuration))
{
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
CGFloat width = CGRectGetWidth([currentTimeSlider bounds]);
interval = 0.5f * duration / width;
}
/* Update the scrubber during normal playback. */
id timeObserver = [player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(interval, NSEC_PER_SEC)
queue:NULL
usingBlock:
^(CMTime time)
{
[self syncScrubber];
NSLog(@"Available: %f",[self availableDuration]);
}];
} else if (player.status == AVPlayerItemStatusUnknown) {
NSLog(@"AVPlayer Unknown");
}
}
}
- (IBAction)currentTimeSliderValueChanged:(id)sender {
CMTime playerDuration = [self playerItemDuration];
double duration = CMTimeGetSeconds(playerDuration);
float minValue = [currentTimeSlider minimumValue];
float maxValue = [currentTimeSlider maximumValue];
double time = CMTimeGetSeconds([player currentTime]);
int32_t timeScale = self.player.currentItem.asset.duration.timescale;
[player seekToTime:CMTimeMake((maxValue - minValue) * time / duration + minValue, 1)];
}
- (NSTimeInterval) availableDuration;
{
int result1 = 0;
NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
if([loadedTimeRanges count]>0)
{
CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
NSTimeInterval result = startSeconds + durationSeconds;
result1 =result;
}
return result1;
}
#pragma mark -
#pragma mark Music scrubber control
/* Cancels the previously registered time observer. */
-(void)removePlayerTimeObserver
{
if (mTimeObserver)
{
[self.player removeTimeObserver:mTimeObserver];
mTimeObserver = nil;
}
}
/* Requests invocation of a given block during media playback to update the movie scrubber control. */
-(void)initScrubberTimer
{
double interval = .1f;
CMTime playerDuration = [self playerItemDuration];
if (CMTIME_IS_INVALID(playerDuration))
{
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
CGFloat width = CGRectGetWidth([self.currentTimeSlider bounds]);
interval = 0.5f * duration / width;
}
/* Update the scrubber during normal playback. */
__weak playerScreenViewController *weakSelf = self;
mTimeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(interval, NSEC_PER_SEC)
queue:NULL /* If you pass NULL, the main queue is used. */
usingBlock:^(CMTime time)
{
[weakSelf syncScrubber];
}];
}
/* Set the scrubber based on the player current time. */
- (void)syncScrubber
{
CMTime playerDuration = [self playerItemDuration];
if (CMTIME_IS_INVALID(playerDuration))
{
currentTimeSlider.minimumValue = 0.0;
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
float minValue = [self.currentTimeSlider minimumValue];
float maxValue = [self.currentTimeSlider maximumValue];
double time = CMTimeGetSeconds([self.player currentTime]);
[self.currentTimeSlider setValue:(maxValue - minValue) * time / duration + minValue];
int minutes = (int)time / 60;
int seconds = (int)time % 60;
NSString *minutes1;
NSString *seconds1;
if (minutes < 10) {
minutes1=[NSString stringWithFormat:@"%02d",minutes];
seconds1=[NSString stringWithFormat:@"%02d",seconds];
}
lblStart.text = [NSString stringWithFormat:@"%@:%@",minutes1,seconds1];
[currentTimeSlider setValue:(maxValue - minValue) * time / duration + minValue];
int difference = duration-time;
if (difference == 0) {
[self removePlayerTimeObserver];
[self btnNext_Click:nil];
}
}
}
/* The user is dragging the movie controller thumb to scrub through the movie. */
- (IBAction)beginScrubbing:(id)sender
{
mRestoreAfterScrubbingRate = [self.player rate];
[self.player setRate:0.f];
/* Remove previous timer. */
[self removePlayerTimeObserver];
}
/* Set the player current time to match the scrubber position. */
- (IBAction)scrub:(id)sender
{
if ([sender isKindOfClass:[UISlider class]] && !isSeeking)
{
isSeeking = YES;
UISlider* slider = sender;
CMTime playerDuration = [self playerItemDuration];
if (CMTIME_IS_INVALID(playerDuration)) {
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
float minValue = [slider minimumValue];
float maxValue = [slider maximumValue];
float value = [slider value];
double time = duration * (value - minValue) / (maxValue - minValue);
[self.player seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC) completionHandler:^(BOOL finished) {
dispatch_async(dispatch_get_main_queue(), ^{
isSeeking = NO;
});
}];
}
}
}
/* The user has released the movie thumb control to stop scrubbing through the movie. */
- (IBAction)endScrubbing:(id)sender
{
if (!mTimeObserver)
{
CMTime playerDuration = [self playerItemDuration];
if (CMTIME_IS_INVALID(playerDuration))
{
return;
}
double duration = CMTimeGetSeconds(playerDuration);
if (isfinite(duration))
{
CGFloat width = CGRectGetWidth([self.currentTimeSlider bounds]);
double tolerance = 0.5f * duration / width;
__weak playerScreenViewController *weakSelf = self;
mTimeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(tolerance, NSEC_PER_SEC) queue:NULL usingBlock:
^(CMTime time)
{
[weakSelf syncScrubber];
}];
}
}
if (mRestoreAfterScrubbingRate)
{
[self.player setRate:mRestoreAfterScrubbingRate];
mRestoreAfterScrubbingRate = 0.f;
}
}
- (BOOL)isScrubbing
{
return mRestoreAfterScrubbingRate != 0.f;
}
-(void)enableScrubber
{
self.currentTimeSlider.enabled = YES;
}
-(void)disableScrubber
{
self.currentTimeSlider.enabled = NO;
}
最佳答案
由于以下代码,我收到了该错误消息:
- (void)didPlay {
if (!_boundaryTimeObserver) {
_boundaryTimeObserver =
[_player addBoundaryTimeObserverForTimes:[NSArray<NSValue *> arrayWithObjects:
[NSValue valueWithCMTime:boundaryTime],
nil]
queue:NULL
usingBlock:^() {}];
}
}
- (void)didStop {
if (_boundaryTimeObserver) {
[_player removeTimeObserver:_boundaryTimeObserver];
// FORGOT TO SET _boundaryTimeObserver to NIL!!!!
}
}
An instance of AVPlayer cannot remove a time observer that was added by a different instance of AVPlayer
可以在给定时间观察者未与 AVPlayer
关联的任何时候发生。这可能是因为它与另一个 AVPlayer
相关联,或者因为它之前已从相关的 AVPlayer
中删除。
关于objective-c - 终止应用程序原因 : 'An instance of AVPlayer cannot remove a time observer that was added by a different instance of AVPlayer.' ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26668230/
我有一个 AVPlayer当我到达持续时间结束时,我想回到开始,但我不想重新启动AVPlayer . //Do something when video ended NotificationCente
我正在使用 AVPlayer 从服务器流式传输音频,我现在想做的是显示一个显示缓冲进度的自定义 UISlider。 有人想出这个吗?请给我解决方案。现在播放器一次加载整个持续时间并在 UISlider
我知道 AVPlayerItem(AVPlayer 的子类)能够订阅 AVPlayerItemDidPlayToEndTimeNotification AVPlayer 没有这样的功能,我需要使用 A
总结: 如果您只使用 AVPlayer 在您的应用程序中播放流音频,那么锁屏更新将工作得很好(许多流 - 一个接一个)。但是,如果您使用 AVPlayer 播放流式音频,然后播放本地视频文件(即使在使
我正在尝试创建像 Vine 这样的应用程序。我有一个 Collection View ,其中每个项目都包含一个带有 AVPlayerLayer 和 AVPlayer 实例的 View ,并且相应的 a
我创建了一个简单的 AVPlayer。 (如果我没有正确创建它,请帮我修复它...😀)我想用 swift ui 在我的 VStack 中显示它,但我有点卡住了... 如果库里至少有AVPlayer
我已将观察者添加到 AVPlayer,但它不会在 avplayer 状态准备好播放时调用该函数。该函数在视频开始播放时调用两次,但 AVPlayer 的持续时间参数都返回“nan”,我需要在 AVPl
我有 2 个 View Controller ,第一个包含一个视频信息列表表,然后从列表中选择一个项目,通过导航打开详细 View Controller 。我在这个细节 Controller 上使用了
关于这个主题的所有线程都非常老(5+ 哟),我似乎无法形成一个清晰的现代方法,所以希望这可以在 2020 年(Swift 5,Xcode 11)进行总结。 如果您要使用 为 iPhone 构建一个 A
我有一个 AVPlayer 可以从网络流式传输 mp3 文件。我已经激活了一个 AVAudioSession 以便在应用程序退出/屏幕关闭时播放音频。音乐播放完美,但手机顶部状态菜单中出现的“播放”三
我正在使用 Apple 的文档演示。这是演示链接: AVPlayerDemo 我的应用程序在执行以下步骤后崩溃了: 1) 播放歌曲 2) 从搜索栏快进。 3)点击下一步,4) 从搜索栏快进。 这是我的
因此看来,实际起作用的唯一值是0.0、0.5、1.0和2.0 ... 我尝试将其设置为0.25,因为我希望它以自然速度的1/4播放,但它却以自然速度的1/2播放。有人可以确认吗? 最佳答案 已确认。实
我有一个应用程序,它通过 AVMutableComposition 将本地文件加载到 avPlayer 中,它可能有多达 6 个音频和视频轨道作为合成的一部分。 我有一个 UISlider,用于调整播
在我的 IOS 应用程序中使用 AVPlayer 显示短视频的屏幕。我成功离开并重新进入此屏幕几次,但在七次或更多次后,我得到空白屏幕并且 AVPlayerLayer 的 IsReadyForDisp
我正在开发一个应用程序,其中包括使用每帧动画播放视频的功能。 您可以看到 example这样的功能。 我已经尝试添加 CAKeyFrameAnimation到 AVSynchronizedLayer
如何在 osx 自动播放中制作 avplayer? 我试过这个: NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"video nam
iOS AVPlayer 的默认最大和最小缓冲区大小是多少?如何增加 mp3 流媒体的大小?谢谢你 最佳答案 如果您的 缓冲区大小 意味着播放缓冲区,那么我相信这个大小没有记录。 此行为由 AVFou
我正在使用多个 AVPlayer 在我的屏幕上显示内容,并且它们都同时播放视频。 问题是有时 avplayer 正在播放,但 avplayerlayer 没有显示任何内容 - 你得到的只是一个空白屏幕
我正在使用 AVPlayer 在我的应用程序中播放视频,现在我想让视频在后台模式下播放。 这是我放入 - (BOOL)application:(UIApplication *)application
我在 iOS 6.1 中使用 AVPlayer 对象。我目前正在连接到 Icecast 服务器以传输现场音乐源。但是,当流由于任何原因(例如重新启动或信号更改)而中断时,AVPlayer 会停止播放。
我是一名优秀的程序员,十分优秀!