我想在AVPlayer中实现Scrubber(UISlider)。我已经尝试过,但是没有完全成功(有时滑块显示不正确的值,有时进度显示进度条)。任何建议都会很棒。
-(void)playButtonClicked
{
// checks internet connnection : working or not
if([InternetUtility testInternetConnection])
{
if (audioButton.selected)
{
audioButton.selected = NO;
printf("\n\ndo audioButton.selected = NO; \n\n");
}
else
{
printf("\n\ndo audioButton.selected = YES; \n\n");
audioButton.selected = YES;
}
if (!isAlredayPlaying) {
printf("\n\nStarted song from 0\n");
isAlredayPlaying=YES;
NSURL *url = [NSURL URLWithString:AUDIO_FILE_URL];
playerItem = [AVPlayerItem playerItemWithURL:url];
player = [AVPlayer playerWithPlayerItem:playerItem];
player.volume=5.0;
[self.audioSliderBar setMinimumValue:0.0];
nsTimer=[NSTimer scheduledTimerWithTimeInterval:1.0/60.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];
[player play];
}
else
{
if (isCurrentlyPlaying)
{
[nsTimer invalidate];
isCurrentlyPlaying=NO;
[player pause];
}
else
{
nsTimer=[NSTimer scheduledTimerWithTimeInterval:1.0/60.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];
isCurrentlyPlaying=YES;
[player play];
}
}
} // internet connection check funtion, ended
else {
[ViewUtilities showAlert:INTERNET_CONNETION_TITLE :INTERNET_CONNECTION_MESSAGE];
}
}
- (void)updateTime:(NSTimer *)timer {
currentTime = CMTimeGetSeconds(playerItem.currentTime);
duration = CMTimeGetSeconds(playerItem.duration);
if (currentTime==duration) {
[self itemDidFinishPlaying];
}
[ self.audioSliderBar setValue:(currentTime/duration)];
float minutes = floor(currentTime/60);
seconds =currentTime - (minutes * 60);
float duration_minutes = floor(duration/60);
duration_seconds =
duration - (duration_minutes * 60);
NSString *timeInfoString = [[NSString alloc]
initWithFormat:@"%0.0f:%0.0f",
minutes, seconds ];//],
//duration_minutes, duration_seconds];
if (!(player.currentItem && player.rate != 0 )&& isCurrentlyPlaying)
{
if (audioPlayerWillStop) {
isAlredayPlaying=NO;
[nsTimer invalidate];
}
else {
[player play];
printf("\n\n\n Force to play song...");
}
}
self.audioCurrentTimeLabel.text = timeInfoString;
}
-(IBAction)audioPlayerValueChanged:(UISlider *)aSlider {
CMTime newSeekTime = CMTimeMakeWithSeconds(aSlider.value*seconds,1) ;
[player seekToTime:newSeekTime];
// 此代码无法完全正常工作(滑块值会不断返回)请帮助
}
您可以使用我的已实现方法。该代码可以正常工作。
#define NSEC_PER_SEC 1000000000ull
-(void)funSeekPlayer
{
CMTime playerDuration = [self playerItemDuration];
if (CMTIME_IS_INVALID(playerDuration)) {
return;
}
float minValue = [aSlider minimumValue];
float maxValue = [aSlider maximumValue];
float value = [aSlider value];
double time = duration * (value - minValue) / (maxValue - minValue);
[player seekToTime:CMTimeMakeWithSeconds(CMTimeMakeWithSeconds(time, NSEC_PER_SEC), NSEC_PER_SEC) completionHandler:^(BOOL finished) {
dispatch_async(dispatch_get_main_queue(), ^{
// Do Your next task
});
}];
}
- (CMTime)playerItemDuration
{
AVPlayerItem *playerItem = [player currentItem];
if (playerItem.status == AVPlayerItemStatusReadyToPlay)
{
return([playerItem duration]);
}
return(kCMTimeInvalid);
}
您必须知道确切的长度(以秒为单位)的音乐/视频。然后,您可以使用UISlider
以秒为单位计算开始播放音乐/视频的时间。最后在您的.seekToTime(CMTimeMake(valueInSecond, 1))
对象上使用了AVPlayer
。
如果您正在使用HLS(m3u8)视频点播流,并且想要向前搜索,则需要等待所有下载的时间范围。这意味着,如果要向前搜索60秒,则AVPlayer应该加载这60秒的所有时间范围。您可以像这样检查:
- (double) loadedTimeRangesDuration
{
double result = 0;
NSArray* ranges = self.player.currentItem.loadedTimeRanges;
if (ranges != nil && ranges.count > 0)
{
CMTimeRange range = [[ranges objectAtIndex:0] CMTimeRangeValue];
double duration = CMTimeGetSeconds(range.duration);
result = duration;
}
return result;
}
对于提前10秒钟移动视频,我已经使用了此代码,它对我有用
浮动tempTime = CMTimeGetSeconds(player.currentItem.duration)+ 10;
CMTime targetTime = CMTimeMakeWithSeconds(tempTime,NSEC_PER_SEC);
[玩家seekToTime:targetTime];