English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Simple Encapsulation and Explanation of Video Players in iOS

Preface

If it is just to play video, both are very simple to use, but compared to MediaPlayer, AVPlayer has stronger controllability for video playback, which can be realized through some custom controls to play, pause, and so on. Therefore, AVPlayer's video playback is used here.

Video player layout

Firstly, use xib to create CLAVPlayerView inheriting UIView to carry the player. This way, when we use it externally, we can directly add CLAVPlayerView to the controller's View or Cell. The operations such as playing or pausing the player are handed over to CLAVPlayerView to manage. Let's take a look at the structure of CLAVPlayerView below.


The structure of CLAVPlayerView

The layout of CLAVPlayerView is simple, focusing on the addition of constraints and the control hierarchy. Adding constraints only requires careful addition one by one, and attention should be paid to the control hierarchy. From the figure above, it can be seen that the four controls are added in parallel to CLAVPlayerView in a sequential order. It is important to pay attention to their hierarchy to avoid mutual occlusion.

Implementation of video player

After the layout is completed, it is time to implement the player function. We divide the player function into four parts to complete

I. Implement video playback through the play button.

Firstly, when CLAVPlayerView is loaded, the player layer needs to be added to the imageView's layer. At this time, the mask and the bottom toolbar are always hidden. Click the middle play button, the video starts playing and the play button is hidden. Therefore, we need to do some processing in the awakeFromNib method of CLAVPlayerView when loading CLAVPlayerView.

1Initialize AVPlayer and AVPlayerLayer, and add AVPlayerLayer to the imageView's layer, set playerLayer's frame in layoutSubviews

// Initialize player and playerLayer
self.player = [[AVPlayer alloc]init];
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
// Add playerLayer to imageView
[self.imageView.layer addSublayer:self.playerLayer];
-(void)layoutSubviews
{
 [super layoutSubviews];
 self.playerLayer.frame = self.imageView.bounds;
}

2Create an AVPlayerItem based on the url of the video being played

NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_02.mp4"];
self.playerItem = [AVPlayerItem playerItemWithURL:url];

3Set the origin and maximum/minimum images of the Slider

// Set Slider
[self.progressSlider setThumbImage:[UIImage imageNamed:@"thumbImage"] forState:UIControlStateNormal];
[self.progressSlider setMaximumTrackImage:[UIImage imageNamed:@"MaximumTrackImage"] forState:UIControlStateNormal];
[self.progressSlider setMinimumTrackImage:[UIImage imageNamed:@"MinimumTrackImage"] forState:UIControlStateNormal];

4、add tap gesture to imageView, click imageView to display the toolbar

//imageView add gesture
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction:)];
[self.imageView addGestureRecognizer:tap];

Note:If gesture is added to imageView using xib, when loading xib through loadNibNamed, it is necessary to get the firstObject of the returned array to get the View of xib. If the lastObject is obtained, it is the tap gesture, which will cause an error that the tap gesture object does not have the View method.

5、set the display and status of other controls

// Hide the cover
self.coverView.hidden = YES;
// Set the status of the toolbar
self.toolView.alpha = 0;
self.isShowToolView = NO;
// Set the status of the toolbar play button
self.playOrPauseBtn.selected = NO;

This cover only appears after the playback is finished, and it is hidden after clicking replay, so we can directly hide it using hidden. However, the toolbar needs to be displayed repeatedly, and in order to make the display of the toolbar have an animation effect, here we set the alpha of toolView to show or hide the toolbar, and record the display or hide of toolView through isShowToolView.

6、click on the middle play button

- (IBAction)playOrPauseBigBtnClick:(UIButton *)sender {
 // Hide the middle play button, and the toolbar play button is in the selected state
 sender.hidden = YES;
 self.playOrPauseBtn.selected = YES;
 // Replace Play Content
 [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
 [self.player play];
 [self addProgressTimer];
}

At this moment, when we click the middle play button, the player can play the video.

Section 2: Display and Hide of the Toolbar

When in the playback state, tapping the imageView will pop up the bottom toolbar, where you can view the current playback time, total video time, or perform operations such as pausing the video, full-screen playback, etc. If no operation is performed, the toolbar will remain5seconds later it will automatically hide. When in the unplayed state, tapping the imageView and the middle playback button have the same effect, starting the video playback.

1Add a timer,5After a few seconds, hide the bottom toolbar and provide a method to remove the timer.

/** Start timing when the toolView is displayed5seconds later hide the toolView */
-(void)addShowTime
{
 self.showTime = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(upDateToolView) userInfo:nil repeats:NO];
 [[NSRunLoop mainRunLoop]addTimer:self.showTime forMode:NSRunLoopCommonModes];
}
/** Hide the toolView */
-(void)upDateToolView
{
 self.isShowToolView = !self.isShowToolView;
 [UIView animateWithDuration:0.5 animations:^{
  self.toolView.alpha = 0;
 };
}
/**Remove the timer*/
-(void)removeShowTime
{
 [self.showTime invalidate];
 self.showTime = nil;
}

2The tap gesture click method implementation of imageView is divided into several cases. When the video is not playing, tapping the imageView will not display the toolbar but will start the video playback as if clicking the middle playback button. During playback, tapping the imageView will display the toolbar. If the pause button in the toolbar is clicked at this time, the playback will pause, and the toolbar will not disappear, resuming the video playback. The toolbar in5disappear within a second.

/** The tap gesture method of imageView */
-(void)tapAction:(UITapGestureRecognizer *)tap
{
 // When in the unplayed state, tapping the imageView is equivalent to tapping the middle playback button, starting the video playback
 if (self.player.status == AVPlayerStatusUnknown) {
  [self playOrPauseBigBtnClick:self.playOrPauseBigBtn];
  return;
 }
 // Record the status of displaying or hiding the bottom toolbar
 self.isShowToolView = !self.isShowToolView;
 // If the toolbar needs to be displayed, add an animation to display
 if (self.isShowToolView){
  [UIView animateWithDuration:0.5 animations:^{
   self.toolView.alpha = 1;
  };
  // When the playback button in the toolbar is in the playback state, add a timer,5Seconds later, the toolbar is hidden
  if (self.playOrPauseBtn.selected) {
   [self addShowTime];
  }
 // If you need to hide the toolbar, remove the timer, and hide the toolbar
 }
  [self removeShowTime];
  [UIView animateWithDuration:0.5 animations:^{
   self.toolView.alpha = 0;
  };
 }
}

3The playback in the toolbar/The click of the pause button also needs some processing, when in pause state, the toolbar alpha value is set to1and the timer is removed when the video is played again, the timer is re-added to start timing,5Seconds later, the toolbar disappears. The specific code will be detailed in the synchronization of playback time, Slider, and video playback.

3. Synchronization of playback time, Slider, and video playback

The playback time, total video time, and Slider sliding in the bottom toolbar need to be synchronized with the video playback time.

1Add video playback and Slider timer, every1Seconds later, the timer repeats to update the time label and Slider slider

 /** Add slider timer */
 -(void)addProgressTimer
 {
  self.progressTimer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(updateProgressInfo) userInfo:nil repeats:YES];
  [[NSRunLoop mainRunLoop]addTimer:self.progressTimer forMode:NSRunLoopCommonModes];
 }
 /** Remove the slider timer */
 -(void)removeProgressTimer
 {
  [self.progressTimer invalidate];
  self.progressTimer = nil;
 }
 /** Update the slider and timeLabel */
 - (void)updateProgressInfo
 {
 NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentTime);
  NSTimeInterval durationTime = CMTimeGetSeconds(self.player.currentItem.duration);
  self.timeLabel.text = [self timeToStringWithTimeInterval:currentTime];
  self.allTimeLabel.text = [self timeToStringWithTimeInterval:durationTime];
  self.progressSlider.value = CMTimeGetSeconds(self.player.currentTime)} / CMTimeGetSeconds(self.player.currentItem.duration);
  if (self.progressSlider.value == 1) {
   [self removeProgressTimer];
   self.coverView.hidden = NO;
  } 
 }

The current playback time and total time obtained are of CMTime type. They need to be converted to NSTimeInterval, and seconds need to be converted to minutes and time. The conversion method should be extracted.

/** The method for converting playback time and total time */
-(NSString *)timeToStringWithTimeInterval:(NSTimeInterval)interval;
{
 NSInteger Min = interval / 60;
 NSInteger Sec = (NSInteger)interval %% 60;
 NSString *intervalString = [NSString stringWithFormat:@"%02ld:%02ld",Min,Sec];
 return intervalString;
}

2When clicking the middle play button to start playback, add a timer to synchronize the update of playback time and Slider. When clicking the pause button on the toolbar during playback, pause the playback, remove the timer, and add the timer and start playback again when restarting.

/** The click event of the pause button on the toolView */
- (IBAction)playOrPauseBtnClick:(UIButton *)sender {
 // The play state button selected is YES, and the pause state selected is NO.
 sender.selected = !sender.selected;
 if (!sender.selected) {
  self.toolView.alpha = 1;
  [self removeShowTime];
  [self.player pause];
  [self removeProgressTimer];
 }
  [self addShowTime];
  [self.player play];
  [self addProgressTimer];
 }
}

3Drag-jump playback of the Slider video

The video playback needs to listen to the three stages of pressing, dragging (data change), and releasing on the Slider. When pressed, the timer is removed; when dragging, the current playback time is calculated based on the dragging value and displayed on the label; when released, the current playback time is calculated and the playback jumps to the current playback time.

/** Slider drag and click events */
- (IBAction)touchDownSlider:(UISlider *)sender {
 // Remove the listener when pressed down
 [self removeProgressTimer];
 [self removeShowTime];
}
- (IBAction)valueChangedSlider:(UISlider *)sender {
 // Calculate the playback time corresponding to the point where the slider is dragged
 NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentItem.duration); * sender.value;
 self.timeLabel.text = [self timeToStringWithTimeInterval:currentTime];
}
- (IBAction)touchUpInside:(UISlider *)sender {
 [self addProgressTimer];
 //Calculate the playback time corresponding to the current slider drag
 NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentItem.duration); * sender.value;
 // seekToTime: Jump to the current playback time
 [self.player seekToTime:CMTimeMakeWithSeconds(currentTime, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
 [self addShowTime];
}

4. Implementation of the replay button and full-screen play button

1In the method called every second by the timer, check if the video has finished playing and display the cover view. The implementation of the replay button is actually to set the Slider's value to 0 and call the method when the Slider is released again, setting the current playback time to 0, hiding the cover view again, and calling the middle play button to start playback.

/** Click on the replay button */
- (IBAction)repeatBtnClick:(UIButton *)sender {
 self.progressSlider.value = 0;
 [self touchUpInside:self.progressSlider];
 self.coverView.hidden = YES;
 [self playOrPauseBigBtnClick:self.playOrPauseBigBtn];
}

2The implementation of full-screen playback

Full-screen playback requires a controller to modal out a full-screen playback controller for full-screen playback, create a full-screen playback controller CLFullViewController, and make it support left and right rotations, modal out the CLFullViewController controller, and add CLAVPlayerView to the View of CLFullViewController and set frame, when exiting full-screen, dismiss CLFullViewController and set the frame of CLAVPlayerView to the original value.
Set rotatable and rotation direction in CLFullViewController

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
 return UIInterfaceOrientationMaskLandscape;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
 return YES;
}

Full screen playback button click event

/** Full screen button click event */
- (IBAction)fullViewBtnClick:(UIButton *)sender {
 sender.selected = !sender.selected;
 [self videoplayViewSwitchOrientation:sender.selected];
}
/** Pop up full-screen player */
- (void)videoplayViewSwitchOrientation:(BOOL)isFull
{
 if (isFull) {
  [self.contrainerViewController presentViewController:self.fullVc animated:NO completion:^{
   [self.fullVc.view addSubview:self];
   self.center = self.fullVc.view.center;
   [UIView animateWithDuration:0.15 delay:0.0 options:UIViewAnimationOptionLayoutSubviews animations:^{
    self.frame = self.fullVc.view.bounds;
   }; completion:nil];
  };
 } else {
  [self.fullVc dismissViewControllerAnimated:NO completion:^{
   [self.contrainerViewController.view addSubview:self];
   [UIView animateWithDuration:0.15 delay:0.0 options:UIViewAnimationOptionLayoutSubviews animations:^{
    self.frame = CGRectMake(0, 200, self.contrainerViewController.view.bounds.size.width, self.contrainerViewController.view.bounds.size.width * 9 / 16);
   }; completion:nil];
  };
 }
}

Note:Here, it is necessary to obtain the external controller to Moda out the full-screen playback controller, so the CLAVPlayerView is added with the contrainerViewController attribute to obtain the controller.

Simple encapsulation

At this point, the basic functions of the player have been implemented. Next, consider how to encapsulate to make it more convenient to use. In fact, most of the encapsulation has been completed. What needs to be done next is to provide a simple and easy-to-use interface so that the external can easily call and implement the player.

1to provide a class method for quickly creating a player

+ (instancetype)videoPlayView
{
 return [[[NSBundle mainBundle] loadNibNamed:@"CLAVPlayerView" owner:nil options:nil] lastObject];
}

2The resource for playing the video should be decided by the external, so we provide the urlString property to receive the video resource and then play the video by rewriting its set method.
/** method for setting the video resource to be played */

-(void)setUrlString:(NSString *)urlString
{
 _urlString = urlString;
 NSURL *url = [NSURL URLWithString:urlString];
 self.playerItem = [AVPlayerItem playerItemWithURL:url];
}

At this time, using the player externally is very simple. There is no need to consider the internal logic. You only need to quickly create a CLAVPlayerView, add it to the controller's View, set its frame, and then specify the video resource it plays.

- (void)viewDidLoad {
 [super viewDidLoad];
 [self setUpVideoPlayView]; 
 self.playView.urlString = @"http://120.25.226.186:32812/resources/videos/minion_02.mp4";
}
-(void)setUpVideoPlayView
{
 self.playView = [CLAVPlayerView videoPlayView];
 self.playView.frame = CGRectMake(0, 200, self.view.frame.size.width, self.view.frame.size.width * 9 / 16);
 self.playView.contrainerViewController = self;
 [self.view addSubview:self.playView];
}

Finally, the video player looks roughly like this

Summary

There are still many places to be improved, some functions have not been implemented yet, such as two placeholder Buttons, which can be used to download videos and control the switch of Danmu in the future. The share button after the playback is also not implemented. I will continue to share with everyone after the implementation. That's all for this article. I hope the content of this article can be helpful to everyone. If you have any questions, you can leave a message for communication.

Statement: The content of this article is from the Internet, the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, does not edit the content manually, and does not bear the relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#oldtoolbag.com (Please replace # with @ when sending an email for reporting, and provide relevant evidence. Once verified, this site will immediately delete the infringing content.)

You May Also Like