AVPlayer for iOS Video Development

Keywords: Attribute network less iOS

AVPlayer here I do not write, reprint a blog written by others, very good, you can see:
Original address: http://www.cnblogs.com/YanPengBlog/p/5280211.html

// MPMovie Player Controller is powerful enough to complete a player without writing a few lines of code, but because of its high encapsulation, customizing the player becomes complex or even impossible. After IOS9, MPMovie Player Controller was abandoned by Apple (though it does not affect normal use). Apple recommends AVPlayerViewController. In short, MPMovie Player Controller is simpler to use and less powerful than AVPlayer, while AVPlayer is slightly more troublesome, but more powerful. For example, sometimes you need to customize the style of the player, so if you want to use MPMovie Player Controller is not appropriate, if you want to have free control of the video, you can use AVPlayer. AVPlayer exists in AV Foundation, which is closer to the bottom, so it is more flexible:

// AVPlayer itself does not display video, and it does not have a view attribute like MPMovie Player Controller. If AVPlayer wants to display, it must create a player layer AVPlayer Layer for display. Player layer inherits from CALayer and can be added to the layer of controller view with AVPlayer Layer. To use AVPlayer, first look at several common classes:

// AVAsset: It's mainly used to get multimedia information. It's an abstract class and can't be used directly.

// AVURLAsset: A subclass of AVAsset that can create an AVURLAsset object containing media information based on a URL path.

// AVPlayerItem: A media resource management object that manages some basic information and status of video. An AVPlayerItem corresponds to a video resource.

Here is a simple demonstration of the use of AVPlayer through a player. The effect of the player is as follows:

Video playback, pause, progress display and video list functions are implemented in this custom player. These functions are described below.

First of all, we will talk about the playback and pause function of video, which is also the most basic function. AVPlayer corresponds to two methods, play and pause. But the key problem is how to judge whether the current video is playing or not. In the previous content, whether the audio player or the video player has the corresponding state to judge. But AVPlayer does not have such state attributes. Usually, it can get the playing state by judging the player's playing speed. If rate is 0, it means stop state, and 1 means normal play state.

Secondly, it is not as simple as other players to show the progress of play. In the previous players, notifications are usually used to get the status of the player, media loading status, etc., but neither AVPlayer nor AVPlayerItem (AVPlayer has an attribute, currentItem is AVPlayerItem type, representing the current video object) can obtain this information. Of course, AVPlayerItem is notified, but there is only one useful notification for getting playback status and load status: Playback completion notification AVPlayerItemDidPlayToEndTime Notification. When playing video, especially playing network video, it is often necessary to know the loading, buffering and playing of video. This information can be obtained by KVO monitoring the status of AVPlayerItem and loading TimeRanges attributes. When the status attribute of AVPlayerItem is AVPlayerStatusReadyToPlay, the information about the video duration can be obtained only when it is playing; when the loaded TimeRanges are changed (the attribute is updated for each part of the buffer), the video range of the buffer loading (including the start time and the load time) can be obtained, so that it can be real-time. Get the buffer. Then it relies on AVPlayer's -(id) addPeriodic Time Observer ForInterval:(CMTime) interval queue:(dispatch_queue_t) queue using Block:(void(^) (CMTime)) block method to get the playback progress. This method updates the playback progress regularly within the set time interval and notifies the client through the time parameter. Believe that with these video information broadcast progress will not be a problem, in fact, through these information, even if it is usually seen in other players buffer progress display and drag play function can also be smoothly realized.

Finally, there is the function of video switching. In all the players mentioned above, each player object can only play one video at a time. If switching video, only one object can be created again. But AVPlayer provides the -(void) replaceCurrent Item WithPlayerItem:(AVPlayerItem*) item method for switching between different videos (in fact, there is also one inside AVFoundation). An AVQueuePlayer specializes in playlist switching. Interested friends can do their own research, which is not discussed here.

//
//  ViewController.m
//  AVPlayer
//
//  Created by Kenshin Cui on 14/03/30.
//  Copyright (c) 2014 cmjstudio. All rights reserved.
//

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>

@interface ViewController ()

@property (nonatomic,strong) AVPlayer *player;//Player object

@property (weak, nonatomic) IBOutlet UIView *container; //Player container
@property (weak, nonatomic) IBOutlet UIButton *playOrPause; //Play/pause button
@property (weak, nonatomic) IBOutlet UIProgressView *progress;//Playback progress

@end

@implementation ViewController

#pragma mark-controller view method
- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupUI];
    [self.player play];
}

-(void)dealloc{
    [self removeObserverFromPlayerItem:self.player.currentItem];
    [self removeNotification];
}

#pragma mark - private method
-(void)setupUI{
    //Create Player Layer
    AVPlayerLayer *playerLayer=[AVPlayerLayer playerLayerWithPlayer:self.player];
    playerLayer.frame=self.container.frame;
    //Player Layer. videoGravity = AVLayer Video GravityResizeAspect; //Video Filling Mode
    [self.container.layer addSublayer:playerLayer];
}

/**
 *  Intercept video thumbnails at specified times
 *
 *  @param timeBySecond Point of time
 */

/**
 *  Initialize Player
 *
 *  @return Player object
 */
-(AVPlayer *)player{
    if (!_player) {
        AVPlayerItem *playerItem=[self getPlayItem:0];
        _player=[AVPlayer playerWithPlayerItem:playerItem];
        [self addProgressObserver];
        [self addObserverToPlayerItem:playerItem];
    }
    return _player;
}

/**
 *  Obtaining AVPlayerItem Objects from Video Index
 *
 *  @param videoIndex Video Sequential Index
 *
 *  @return AVPlayerItem object
 */
-(AVPlayerItem *)getPlayItem:(int)videoIndex{
    NSString *urlStr=[NSString stringWithFormat:@"http://192.168.1.161/%i.mp4",videoIndex];
    urlStr =[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url=[NSURL URLWithString:urlStr];
    AVPlayerItem *playerItem=[AVPlayerItem playerItemWithURL:url];
    return playerItem;
}
#pragma mark - Notification
/**
 *  Add Player Notification
 */
-(void)addNotification{
    //Add Play Completion Notification to AVPlayerItem
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
}

-(void)removeNotification{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

/**
 *  Play Completion Notice
 *
 *  @param notification Notification object
 */
-(void)playbackFinished:(NSNotification *)notification{
    NSLog(@"Video playback completed.");
}

#pragma mark - monitoring
/**
 *  Add progress updates to the player
 */
-(void)addProgressObserver{
    AVPlayerItem *playerItem=self.player.currentItem;
    UIProgressView *progress=self.progress;
    //Here it is set to execute once a second.
    [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        float current=CMTimeGetSeconds(time);
        float total=CMTimeGetSeconds([playerItem duration]);
        NSLog(@"It is currently playing.%.2fs.",current);
        if (current) {
            [progress setProgress:(current/total) animated:YES];
        }
    }];
}

/**
 *  Add monitoring to AVPlayerItem
 *
 *  @param playerItem AVPlayerItem object
 */
-(void)addObserverToPlayerItem:(AVPlayerItem *)playerItem{
    //Monitor status attributes. Note that AVPlayer also has status attributes. By monitoring its status, you can also get playback status.
    [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    //Monitor network load status attributes
    [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
}
-(void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem{
    [playerItem removeObserver:self forKeyPath:@"status"];
    [playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
}
/**
 *  Monitor player status through KVO
 *
 *  @param keyPath Monitoring attribute
 *  @param object  monitor
 *  @param change  State change
 *  @param context context
 */
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    AVPlayerItem *playerItem=object;
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerStatus status= [[change objectForKey:@"new"] intValue];
        if(status==AVPlayerStatusReadyToPlay){
            NSLog(@"Playing now...,Total Video Length:%.2f",CMTimeGetSeconds(playerItem.duration));
        }
    }else if([keyPath isEqualToString:@"loadedTimeRanges"]){
        NSArray *array=playerItem.loadedTimeRanges;
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//The buffer time range
        float startSeconds = CMTimeGetSeconds(timeRange.start);
        float durationSeconds = CMTimeGetSeconds(timeRange.duration);
        NSTimeInterval totalBuffer = startSeconds + durationSeconds;//Total buffer length
        NSLog(@"Co buffer:%.2f",totalBuffer);
//
    }
}

#pragma mark - UI event
/**
 *  Click the Play/pause button
 *
 *  @param sender Play/pause button
 */
- (IBAction)playClick:(UIButton *)sender {
//    AVPlayerItemDidPlayToEndTimeNotification
    //AVPlayerItem *playerItem= self.player.currentItem;
    if(self.player.rate==0){ //Pause at announcement
        [sender setImage:[UIImage imageNamed:@"player_pause"] forState:UIControlStateNormal];
        [self.player play];
    }else if(self.player.rate==1){//Playing now
        [self.player pause];
        [sender setImage:[UIImage imageNamed:@"player_play"] forState:UIControlStateNormal];
    }
}


/**
 *  Switch the selector, where the tag of the button represents the video name
 *
 *  @param sender Click on the button object
 */
- (IBAction)navigationButtonClick:(UIButton *)sender {
    [self removeNotification];
    [self removeObserverFromPlayerItem:self.player.currentItem];
    AVPlayerItem *playerItem=[self getPlayItem:sender.tag];
    [self addObserverToPlayerItem:playerItem];
    //Switching video
    [self.player replaceCurrentItemWithPlayerItem:playerItem];
    [self addNotification];
}

@end

So far, both MPMovie Player Controller and AVPlayer are quite powerful in playing video, but it also has some unavoidable problems, that is, the supporting video coding formats are very limited: H.264, MPEG-4, extension (compressed format):.mp4,.mov,.m4v,.m2v,.3gp,.3g2 and so on. But both MPMovie Player Controller and AVPlayer support the vast majority of audio coding, so you can consider using these two players if you're just playing music. So how to support more video coding formats? At present, it mainly relies on third-party frameworks. The commonly used video coding and decoding frameworks on iOS are VLC and ffmpeg. The specific use methods are no longer described in detail today.

Posted by GB_001 on Wed, 17 Apr 2019 17:57:33 -0700