AVPlayer Progress slider change with user dragging it - ios

I am using AVPlayer, and its working good.
I put slider and it is progression according to player duration.
But i want if user drags slider then play time changes accordingly. i.e. Song forwards or backwards according to slider position.
I have tried
-(IBAction)sliderChange:(id)sender{
[player pause];
CMTime t = CMTimeMake(slider.value,1);
[player seekToTime:t];
[player play];
}
But it again takes slider to starting point. Any help would be much appreciated.
EDIT (WORKING WITH BELOW LINK)
AVPlayer Video SeekToTime

-(IBAction) valueChangeSliderTimer:(id)sender{
[avplayer pause];
isPlaying = FALSE;
[btnPauseAndPlay setTitle:#"Play" forState:UIControlStateNormal];
float timeInSecond = sliderTimer.value;
timeInSecond *= 1000;
CMTime cmTime = CMTimeMake(timeInSecond, 1000);
[avplayer seekToTime:cmTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
}
Edited Code .
And try this link as well :
Try this link

Related

iOS 10 - AVPlayer shows black screen when playing video

Here I have a method that adds the video layer to the UIView that I have setup in IB:
-(void)loadPlayer{
self.asset = [AVAsset assetWithURL:url];
AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:self.asset];
self.player = [AVPlayer playerWithPlayerItem:item];
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.contentsGravity = AVLayerVideoGravityResizeAspect;
self.player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
item.videoComposition = [AVVideoComposition videoCompositionWithPropertiesOfAsset:self.asset];
[self.player pause];
[self.player addObserver:self forKeyPath:#"status" options:0 context:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[self.videoLayer.layer addSublayer:self.playerLayer];
});
}
The above method gets called in the viewDidAppear of the View Controller, so each time the current View Controller loads, the video should start to play.
Here I check for the player status and play the asset if ready:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if (object == self.player && [keyPath isEqualToString:#"status"]) {
if (self.player.status == AVPlayerStatusReadyToPlay) {
[self.player play];
}
}
}
The problem is that the view did appear, the video starts playing, but only the audio, not video. All I get is black screen in the place of video. Audio is playing back fine, but it does not seem to render the video frames for some reason unknown.
This happens only on iOS 10 devices, the same code when run on a iOS 9 devices, works like a charm. The video shows up as expected.
Is there anything that is changed in the AVFoundation framework for iOS 10 in terms of AVPlayer or so? Or is there anything that I am missing here, coz iOS 9 plays it good.
If anyone has faced this issue, and if you have solved it, please post your solution. It would be helpful.
Thanks.
THE SOLUTION
Thanks for your replies! I just found that, for some reason in iOS 10 the viewDidLayoutSubviews did not get called as it was in iOS 9. Actually I was setting the player layer's frame in the viewDidLayoutSubviews method. Since it didn't get called, I was not able to see the player on screen. What I did was, set the player layer's frame in the loadPlayer method above. And it works fine. Hope this helps someone.
This is the line of code that I moved from viewDidLayoutSubviews to my loadPlayer method and it worked:
self.playerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
You need to retain your instance of AVPlayerItem i.e. as a property or an instance variable. The reference to the movie player is lost if you do not retain it.
Even some time this rubish happens in ARC as well.Please make it property.
In my case this problem was because i started playing simultaneously with UIView.animate with view.layoutIfNeeded() in animation block.
The fix for that is to not animate layout changes when not needed and not animate when starting playing video.
The solutions on this page did not work for me.
I found another solution to this problem. In my case the video was being played in black but the sound was ok.
I discovered that changing the time slider to scrub the video would make the video appear.
So, my solution was to make the video go the the last frame, then to the first before playing:
Float64 duration = [self.player duration];
[self.player goToTime:duration];
[self.player goToTime:0.0f];
The black color is background color of the AVPlayerViewController. so change the background color of the AVPlayerViewController as superview color. So the black flash will not be visible.
self.view.backgroundColor =[UIColor whiteColor];
avMoviePlayer.view.backgroundColor=[UIColor whiteColor];
[self.view addSubview:avMoviePlayer.view];
Thanks for your replies! I just found that, for some reason in iOS 10 the viewDidLayoutSubviews did not get called as it was in iOS 9. Actually I was setting the player layer's frame in the viewDidLayoutSubviews method. Since it didn't get called, I was not able to see the player on screen. What I did was, set the player layer's frame in the loadPlayer method above.And it works fine. Thanks! Hope this helps someone.
EDIT
This is the line of code that I moved from viewDidLayoutSubviews to my loadPlayer method and it worked:
self.playerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
here is what I recently studied for AVPlayer
you can try it
XYAVMoviePlayer
enjoy your day :)

iOS - AVPlayer seekToTime restarts playback of currentItem

I'm making an app that uses AVPlayer. In one of my views I have a UISlider with which the user should be able to scrub forward and backward. I'm having some trouble getting seekToTime to work as I want. When I try to change time the playback starts from 0, and I'm not sure how to solve this. My current implementation looks like this:
[self.progressSlider addTarget:self action:#selector(sliderValueChanged) forControlEvents:UIControlEventValueChanged];
[self.progressSlider addTarget:self action:#selector(sliderReleased) forControlEvents:UIControlEventTouchUpInside];
- (void)sliderValueChanged {
[...]
[player pause];
}
- (void)sliderReleased {
float timeInSecond = self.progressSlider.value;
timeInSecond *= 1000;
// I have trie to hard code this value, but I get the same result.
CMTime cmTime = CMTimeMake(timeInSecond, NSEC_PER_SEC);
[player.currentItem seekToTime:cmTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
if (finished) {
[player play];
}
}];
}
Any ideas on what I'm doing wrong?
Can mention that I stream audio using AVPlayer's: playerItemWithURL if that makes any difference.
One problem is that NSEC_PER_SEC is 1,000,000,000, so CMTimeMake(timeInSecond, NSEC_PER_SEC) is going to be a really tiny number (unless timeInSecond is ridiculously huge) - in fact, it will be arbitrarily close to zero, which is exactly what you are experiencing.
Just to be clear: CMTimeMake defines a rational number. You are giving a numerator and a denominator. If your denominator is huge, the rational number will be tiny.

UISlider change value for online track playing

As always after a lot of searching I back here to get help
my app playing sounds from url, I track the sound playing in uislider by update slider value when start the streamer playing
progressUpdateTimer =
[NSTimer
scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(updateProgress:)
userInfo:nil
repeats:YES];
- (void)updateProgress:(NSTimer *)updatedTimer
{
[progressView setValue: progress / duration];
}
this is my action for change slider value ( forward / backward the track)
- (IBAction)sliderMoved:(UISlider *)aSlider
{
if (streamer.duration)
{
double newSeekTime = (aSlider.value) * streamer.duration;
[streamer seekToTime:newSeekTime];
}
}
What I want is when the user change the slider the value updates instantly without late of loading .. I mean change the slider value then load the sound
But what happened is by dragging the slider thumb to x position , it backs to its position and then move to x when sound loaded
How can I do that ? any help will be appreciated

Accuracy issue in jump to particular section of video in MPMoviePlayerController

in my app i want to add feature . swipe on video take the video to next 2 sec from current playback time. but my player not doing this accurate and exact according to time which i pass to function it jump the current play back time at any where else. i already search a lot and found may be this is due to key-frame of my video i think i need to increase key-frame of video if yes
then (1) what is the best way to increase key-frame of video?
if this issue can solve without increasing key-frame then
(2) how can i do this ?
here is my code
-(void) handleOneFingerSwipeRight
{
if(labelTimer.isValid)
[labelTimer invalidate];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(signleTap) object:nil];
[videoPlayer pause];
double d = 0;
d = floor([videoPlayer currentPlaybackTime]);
d = d+2.0;
NSLog(#"current time %f",floor([videoPlayer currentPlaybackTime]));
NSLog(#"new time %f",d);
[videoPlayer setCurrentPlaybackTime:d];
[videoPlayer play];
[self setLable:[NSString stringWithFormat:#"Adaptive Forward %f",d]];
}

AVPlayer provide wrong currenttime and duration iOS when seek the video many times?

I use use AVPlayer to implement a custom player.
Some video playerItem provide the current time and wrong duration. After to seek time use slide to seek time many times. Call the API
When I seek to zero, some video can not be precisely seeked.
[self.player seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC)
toleranceBefore:CMTimeMake(1, 1)
toleranceAfter:CMTimeMake(1, 1)
completionHandler:^(BOOL finished) {
if (finished) {
IVCLogV(#"seek finish!");
}
else
{
IVCLogV(#"seek interrupted");
}
if (completionHandle) {
completionHandle(finished);
}
}];
I change the codes according the mediaTime.timeScale. Now I discover the video stream have changed the video duration and current time after several play.
Make sure that the Timescale of the media being played matches with your timescale. I can see you have used NSEC_PER_SEC as timescale. You may have to scale your CMTime input to seelTo method.
CMTime timeAccordingToMediaTimescale = CMTimeConvertScale(time, mediaTime.timescale, CMTimeRoundingMethod);

Resources