How can I control "Done" button event of AVPlayer in iOS 8? - ios

I need some code to capture "Done" button click event for AVPlayer in iOS. I am able to get play/pause events using the following code
-(IBAction)play_pressed:(id)sender{
NSURL *videoURL = [NSURL URLWithString:#"http://qthttp.apple.com.edgesuite.net/1010qwoeiuryfg/sl.m3u8"];
self.player = [AVPlayer playerWithURL:videoURL];
self.avPlayerViewcontroller = [AVPlayerViewController new];
self.avPlayerViewcontroller.player = self.player;
self.avPlayerViewcontroller.view.frame = self.view.frame;
[self.player addObserver:self forKeyPath:#"rate" options:0 context:nil];
[self presentViewController:self.avPlayerViewcontroller animated:YES completion:nil];
[self.player play];}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"rate"]) {
if ([self.player rate]) {
NSLog(#"Playing");
}
else {
NSLog(#"Paused");
}
}

Related

How to sync multiple AVPlayer while play the same local video

I have to play the same local video file with the AVPlayer at the same time, and I created 4 AVPlayer instance, and the AVPlayerLayers was added to tha same layer. But the question is that 4 player were not begin at the same time. How to make them begin at the same time? here is my code:
self.players = #[].mutableCopy;
CMAudioClockCreate(kCFAllocatorDefault, &_syncClock);
AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:self.url];
for (NSInteger i = 0; i<playerNum; i++) {
AVPlayer *avPlayer = [AVPlayer playerWithPlayerItem:item.copy];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:avPlayer];
//设置模式
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
playerLayer.contentsScale = [UIScreen mainScreen].scale;
CGPoint pos = [playerOriginArr[i] CGPointValue];
playerLayer.frame = CGRectMake(pos.x, pos.y, playerSize.width, playerSize.height);
[self.playBackBgView.layer addSublayer:playerLayer];
avPlayer.masterClock = _syncClock;
[avPlayer.currentItem addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionNew context:nil];
[avPlayer play];
[self.players addObject:avPlayer];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"status"] && [object isKindOfClass:[AVPlayerItem class]]) {
AVPlayerItem *playerItem = (AVPlayerItem *)object;
if (playerItem.status == AVPlayerStatusReadyToPlay) {
for (AVPlayer *player in self.players) {
if (player.currentItem == playerItem) {
[player prerollAtRate:1.0 completionHandler:^(BOOL finished) {
if (finished) {
}
}];
player.automaticallyWaitsToMinimizeStalling = NO;//如果是
NSLog(#"setRate");
[player setRate:1.0 time:kCMTimeInvalid atHostTime:CMClockGetTime(_syncClock)];
}
}
}
}
}
Create just one AVPlayer and create multiple AVPlayerLayers from that.
The layers will be synchronized.

AvPlayer streaming, all the metadata information are in timedMetadata?

I'm creating an ios app with a streaming player maded with AvPlayer. This is my code:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self InitPlayer];
[self ReadMetaData];
}
-(void)InitPlayer{
NSURL *url = [[NSURL alloc] initWithString:#"http://www.fakeurl.com/stream"];
// create a player view controller
self.player = [AVPlayer playerWithURL:url];
player.closedCaptionDisplayEnabled = NO;
}
-(void)ReadMetaData{
[self.player.currentItem addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:nil];
}
- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object
change:(NSDictionary*)change context:(void*)context {
if ([keyPath isEqualToString:#"timedMetadata"])
{
AVPlayerItem* playerItem = object;
for (AVMetadataItem* metadata in playerItem.timedMetadata)
{
if([metadata.commonKey isEqualToString:#"title"]){
TitleLabel.text=metadata.stringValue;
}
}
}
}
With this code i can successfully play and pause the stream. I can also print the title of the track.
If i try to log the timedMetadata with something like this:
NSLog(#"%#",player.currentItem.timedMetadata);
I retrive that:
"<AVMetadataItem: 0x15649500, identifier=common/title, keySpace=comn, key class = __NSCFConstantString, key=title, commonKey=title, extendedLanguageTag=(null), dataType=(null), time={21888/44100 = 0.496}, duration={INVALID}, startDate=(null), extras={\n}, value=Keepin-'fake song title>"
Now my question is: for that specific stream url the timedMetadata i logged are the only metadata i can retrive? If yes how i can achive a more complex player type (something like "go to next track button","go to previous track button","an history of tracks",ecc...) ? That's the first time i work with stream data and in my expectations there was a lot of information in audio metadata. In real life seems i can get only the track title. There's a problem with my code or the stream source is poor in metadata info?
I tried to find best solution to get metadata from AVPlayer and found it:
-(IBAction) BtnGoClick:(id)sender {
NSURL *url = [[NSURL alloc] initWithString:#"http://cast.loungefm.com.ua/loungefm"];
[self setupAVPlayerForURL:url];
}
-(void) setupAVPlayerForURL: (NSURL*) url {
AVAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
AVPlayerItem *anItem = [AVPlayerItem playerItemWithAsset:asset];
player = [AVPlayer playerWithPlayerItem:anItem];
[player addObserver:self forKeyPath:#"status" options:0 context:nil];
[anItem addObserver:self forKeyPath:#"timedMetadata" options:NSKeyValueObservingOptionNew context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == player && [keyPath isEqualToString:#"status"]) {
if (player.status == AVPlayerStatusFailed) {
NSLog(#"AVPlayer Failed");
} else if (player.status == AVPlayerStatusReadyToPlay) {
NSLog(#"AVPlayer Ready to Play");
} else if (player.status == AVPlayerItemStatusUnknown) {
NSLog(#"AVPlayer Unknown");
}
}
if ([keyPath isEqualToString:#"timedMetadata"])
{
AVPlayerItem* playerItem = object;
for (AVMetadataItem* metadata in playerItem.timedMetadata)
{
if([metadata.commonKey isEqualToString:#"title"]){
NSLog(#"%#",metadata.stringValue);
}
}
}
}
Result:

AVPlayer starts to reproduce a video after a long delay

Delay is about 10 seconds.
Snippet of my code. It's *.m file of HomeController:
#interface HomeController ()
#property(nonatomic, strong) AVPlayerViewController *playerViewController;
#implementation HomeController
- (void)viewDidLoad
{
[super viewDidLoad];
...
self.playerViewController = [[AVPlayerViewController alloc] init];
}
- (IBAction)watchDemoToggle:(id)sender {
NSURL *url = [NSURL URLWithString:#"http://blahblahblah.com/demo.mp4"];
AVURLAsset *asset = [AVURLAsset assetWithURL: url];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
if(playerItem)
{
AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
self.playerViewController.player = player;
[self.playerViewController.player addObserver:self forKeyPath:#"status" options:0 context:nil];
[self.playerViewController setShowsPlaybackControls:NO];
[self presentViewController:self.playerViewController animated:YES completion:^{
[self.playerViewController.player play];
self.playerViewController.showsPlaybackControls = YES;
}];
}
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqualToString:#"status"]) {
AVPlayerStatus status = [change[NSKeyValueChangeNewKey] integerValue];
NSLog(#"status = %ld", (long)status);
}
}
I added KVO and got result that after click play player status is AVPlayerStatusUnknown. After that it is not changing despite the fact that the video is reproducing.
Does anyone have any idea?
set automaticallyWaitsToMinimizeStalling property of AVPlayer to false in order to start playback immediately.
AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:playerItem];
player.automaticallyWaitsToMinimizeStalling = false;
But if sufficient content is not available for playing then player might stall.
for more details please refer this Apple documentation.
avplayer

iOS AVPlayer stuck

I am using AVPlayer for playing remote .mp4 files (in Objective C). The video loads from remote url, but after 1 sec of playing the player freeze. The video got stucked and not playing it.
Can any one please help me?
NSString *encodedString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *videoUrl = [[NSURL alloc]initWithString:encodedString];
self.asset = [AVAsset assetWithURL:videoUrl];
self.player = [AVPlayer playerWithURL:videoUrl];
self.player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.player addObserver:self forKeyPath:#"status" options:0 context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[self.player currentItem]];
self.playerLayer.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[self.myPlayerView.layer addSublayer:self.playerLayer];
self.videoPlaybackPosition = 0;
[self.player play];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == self.player && [keyPath isEqualToString:#"status"]) {
if (self.player.status == AVPlayerStatusFailed) {
NSLog(#"AVPlayer Failed --> %ld",(long)self.player.currentItem.status);
} else if (self.player.status == AVPlayerStatusReadyToPlay) {
NSLog(#"AVPlayerStatusReadyToPlay");
[self.player play];
} else if (self.player.status == AVPlayerItemStatusUnknown) {
NSLog(#"AVPlayer Unknown");
}
}
}

AVPlayerViewController not playing video and showing Quicktime logo

I am trying to play video with new AVPlayerViewController introduced in XCode 6.
To play video i have done this setup.
Using local mp4 file to play video
Extended AVPlayerViewController
Player setup code :
-(void)setupPlayer
{
NSString* filePath = [[NSBundle mainBundle] pathForResource:#"exodus_trailer" ofType:#"mp4"];
NSLog(#"File Path : %#",filePath);
AVAsset *avAsset = [AVAsset assetWithURL:[NSURL URLWithString:filePath]];
AVPlayerItem *avPlayerItem =[[AVPlayerItem alloc]initWithAsset:avAsset];
self.player = [[AVPlayer alloc]initWithPlayerItem:avPlayerItem];
[self.player addObserver:self forKeyPath:#"status" options:0 context:nil];
[self.player play];
}
KVO handling :
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == self.player && [keyPath isEqualToString:#"status"])
{
if (self.player.status == AVPlayerStatusFailed)
{
NSLog(#"AVPlayer Failed");
}
else if (self.player.status == AVPlayerStatusReadyToPlay)
{
NSLog(#"AVPlayerStatusReadyToPlay");
[self.player play];
}
else if (self.player.status == AVPlayerItemStatusUnknown)
{
NSLog(#"AVPlayer Unknown");
}
}
}
Issue :
KVO log is printing AVPlayerStatusReadyToPlay and file path seems ok. Previously view was at least showing player with all default controls, but now without any changes it started to show Quick time logo without any control. What is meaning of showing this logo ? what i am doing wrong here ?
Screenshot :
Here is exactly like what you wanted to do. The problem with your code is that you are not using file path, use this to load the file path NSURL *url = [NSURL fileURLWithPath:urlString]
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *urlString = [[NSBundle mainBundle] pathForResource:#"testfile" ofType:#"mp4"];
NSURL *url = [NSURL fileURLWithPath:urlString];
self.player = [[AVPlayer alloc] initWithURL:url];
[self.player addObserver:self forKeyPath:#"status"
options:NSKeyValueObservingOptionNew
context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (object == self.player) {
AVPlayerStatus status = [change[NSKeyValueChangeNewKey] integerValue];
if (status == AVPlayerStatusReadyToPlay) {
[self.player play];
[self.player removeObserver:self forKeyPath:#"status"];
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#end

Resources