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

iOSで簡単なビデオプレイヤーのエンキャプシュメントの詳細

前書き

ビデオ再生のみなら、両方の使用は非常に簡単ですが、MediaPlayerに比べて、AVPlayerはビデオ再生の制御性が強く、カスタムコントロールを使用して再生、一時停止などの操作を実現できます。したがって、ここではAVPlayerのビデオ再生を使用します。

ビデオプレイヤーのレイアウト

まず、xibを使用してCLAVPlayerViewをUIViewを継承するように作成し、プレイヤーを保持します。外部で使用する際には、コントローラーのViewまたはCellにCLAVPlayerViewを直接追加するだけで、プレイヤーの再生や一時停止などの操作はCLAVPlayerViewが管理します。次に、CLAVPlayerViewの構造を見てみましょう。


CLAVPlayerViewの構造

CLAVPlayerViewのレイアウトは非常にシンプルで、重点は制約の追加とコントロールのレイアウト関係にあります。制約の追加は、個々に注意深く追加するだけで問題ありません。コントロールのレイアウト関係に注意し、相互に隠れてしまうことがないようにしましょう。上の図から見て、4つのコントロールは順番に平行にCLAVPlayerViewに追加されています。レイアウト関係に注意してください。

ビデオプレイヤー実現

レイアウトが完了した後、プレイヤー機能を実現します。プレイヤー機能は、大まかに4つの部分に分けて完成させます

一. 再生ボタンを通じてビデオ再生を実現

まず、CLAVPlayerViewが読み込まれた際にはプレイヤーライヤーをimageViewのlayerに追加する必要があります。この時、マスクおよび下部ツールバーは必ず非表示です。中央の再生ボタンをクリックすると、ビデオが再生され、再生ボタンが非表示になります。したがって、CLAVPlayerViewのawakeFromNibメソッドで、CLAVPlayerViewが読み込まれた際にいくつかの処理を行う必要があります。

1、AVPlayerおよびAVPlayerLayerを初期化し、AVPlayerLayerをimageViewのlayerに追加し、layoutSubviewsでplayerLayerのframeを設定

// playerおよびplayerLayerの初期化
self.player = [[AVPlayer alloc]init];
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
// imageViewにplayerLayerを追加
[self.imageView.layer addSublayer:self.playerLayer];
-(void)layoutSubviews
{
 [super layoutSubviews];
 self.playerLayer.frame = self.imageView.bounds;
}

2、再生するビデオのURLに基づいてAVPlayerItemを作成

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

3、スライダーの原点および最大点最小点の画像の設定

// スライダーの設定
[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、imageViewにtapジェスチャーを追加し、imageViewをクリックするとツールバーが表示されます

//imageViewにジェスチャーを追加
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapAction:)];
[self.imageView addGestureRecognizer:tap];

注意:xibを使用してimageViewにジェスチャーを追加する場合、loadNibNamedでxibをロードする際には、firstObjectを取得する必要があります。取得したのはxibのViewです。lastObjectを取得すると、tapジェスチャーが得られ、tapジェスチャーがViewを持っていないためエラーが発生します。

5、他のコントロールの表示および状態の設定

// カバーを非表示に
self.coverView.hidden = YES;
// ツールバーの状態を設定
self.toolView.alpha = 0;
self.isShowToolView = NO;
// ツールバーの再生ボタン状態を設定
self.playOrPauseBtn.selected = NO;

このカバーは再生が完了した後に表示され、再生を再開すると非表示になります。したがって、hiddenを使用して直接非表示にすることができますが、ツールバーは再表示が必要です。また、ツールバーの表示にアニメーション効果を追加するために、ここではtoolViewのalphaを設定してツールバーを表示または非表示にし、isShowToolViewを使用してtoolViewの表示または非表示を記録します。

6、中央の再生ボタンのクリック

- (IBAction)playOrPauseBigBtnClick:(UIButton *)sender {
 // 中央の再生ボタンを非表示にし、ツールバーの再生ボタンは選択状態です
 sender.hidden = YES;
 self.playOrPauseBtn.selected = YES;
 // 再生内容を置き換える
 [self.player replaceCurrentItemWithPlayerItem:self.playerItem];
 [self.player play];
 [self addProgressTimer];
}

その時、中央の再生ボタンをクリックすると、プレーヤーが動画を再生します。

二. ツールバーの表示と非表示

再生状態で、imageViewをタップすると下部ツールバーが弹出し、現在の再生時間、ビデオの合計時間を確認したり、ビデオの一時停止、フルスクリーン再生などの操作を行うことができます。何もしませんでしたら、ツールバーは5秒後に自動的に非表示にします。再生されていない状態で、imageViewをタップすると中央の再生ボタンをタップしたのと同じでビデオを再生します。

1、タイマーを追加します。5秒後に下部ツールバーを非表示にし、タイマーを削除する方法を提供します。

/** toolViewが表示されている場合、計時を開始します。5秒後に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];
}
/** toolViewを非表示にします。 */
-(void)upDateToolView
{
 self.isShowToolView = !self.isShowToolView;
 [UIView animateWithDuration:0.5 animations:^{
  self.toolView.alpha = 0;
 };
}
/**タイマーを削除します。*/
-(void)removeShowTime
{
 [self.showTime invalidate];
 self.showTime = nil;
}

2、imageViewのタップジェスチャーのメソッド実装、ここではいくつかの状況に分かれています。ビデオが再生されていない場合、imageViewをタップするとツールバーは表示されず、中央の再生ボタンをタップしたのと同じでビデオを再生します。再生中にimageViewをタップするとツールバーが表示され、その際にツールバーの一時停止ボタンをタップすると再生が一時停止し、ツールバーは消えません。再び再生を開始します。ツールバーは、5秒以内に消えます。

/** imageViewのタップジェスチャーのメソッド */
-(void)tapAction:(UITapGestureRecognizer *)tap
{
 // 再生されていない状態で、imageViewをタップすると中央の再生ボタンをタップしたのと同じで、ビデオの再生を開始します。
 if (self.player.status == AVPlayerStatusUnknown) {
  [self playOrPauseBigBtnClick:self.playOrPauseBigBtn];
  return;
 }
 // 下部ツールバーの表示または非表示の状態を記録します。
 self.isShowToolView = !self.isShowToolView;
 // ツールバーを表示する必要がある場合、アニメーション表示を追加します。
 if (self.isShowToolView){
  [UIView animateWithDuration:0.5 animations:^{
   self.toolView.alpha = 1;
  };
  // ツールバーの再生ボタンが再生状態の場合、タイマーを追加します。5毎秒之后工具栏隐藏
  if (self.playOrPauseBtn.selected) {
   [self addShowTime];
  }
 // 如果需要隐藏工具栏,移除计时器,并将工具栏隐藏
 }
  [self removeShowTime];
  [UIView animateWithDuration:0.5 animations:^{
   self.toolView.alpha = 0;
  };
 }
}

3、工具栏中播放/暂停按钮的点击也需要做一些处理,当处于暂停状态时,工具栏alpha值设为1、并将定时器移除,重新开始播放视频时,则重新添加定时器开始计时,5毎秒钟之后让工具栏消失。具体代码会在播放时间、Slider与视频播放的同步中详细贴出。

三. 播放时间、Slider与视频播放的同步

底部工具条中播放时间、视频总时间以及Slider的滑动需要与视频播放时间进行同步。

1、添加视频播放和Slider的定时器,每1毎秒重复调用更新时间label和Slider滑块

 /** slider定时器添加 */
 -(void)addProgressTimer
 {
  self.progressTimer = [NSTimer timerWithTimeInterval:1.0 目標:self selector:@selector(updateProgressInfo) userInfo:nil repeats:YES];
  [[NSRunLoop mainRunLoop]addTimer:self.progressTimer forMode:NSRunLoopCommonModes];
 }
 /** 移除slider定时器 */
 -(void)removeProgressTimer
 {
  [self.progressTimer invalidate];
  self.progressTimer = nil;
 }
 /** 更新slider和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;
  } 
 }

現在の再生時間と合計時間はCMTime型であり、それらをNSTimeIntervalに変換し、秒を分と時間に変換する必要があります。変換方法を抽出します。

/** 再生時間と合計時間を変換する方法 */
-(NSString *)timeToStringWithTimeInterval:(NSTimeInterval)interval;
{
 NSInteger Min = interval / 60;
 NSInteger Sec = (NSInteger)interval %% 60;
 NSString *intervalString = [NSString stringWithFormat:@"%02ld:%02ld",Min,Sec];
 return intervalString;
}

2、中間の再生ボタンをクリックして再生を開始するときにタイマーを追加し、再生時間とSliderを同期して更新し、再生中にツールバーの一時停止ボタンをクリックして再生を一時停止するときは、ビデオを一時停止し、タイマーを削除し、再開時にタイマーを追加し、再生を開始します。

/** toolView上の一時停止ボタンのクリックイベント */
- (IBAction)playOrPauseBtnClick:(UIButton *)sender {
 // 再生状態のボタンselectedがYES、一時停止状態のselectedが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];
 }
}

3、Sliderのドラッグジャンプでビデオを再生

Sliderのスライドをドラッグして位置を移動してビデオを再生する場合、Sliderの押下、ドラッグ(データが変更される)、リリースの3つの段階を監听する必要があります。押下時はタイマーを削除し、ドラッグ時はドラッグの値に基づいて現在の再生時間を即座に計算し、labelに表示し、リリース時は現在の再生時間を計算し、その再生時間にジャンプして再生します。

/** slider拖动和点击事件 */
- (IBAction)touchDownSlider:(UISlider *)sender {
 // 按下去 移除监听器
 [self removeProgressTimer];
 [self removeShowTime];
}
- (IBAction)valueChangedSlider:(UISlider *)sender {
 // 计算slider拖动的点对应的播放时间
 NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentItem.duration) * sender.value;
 self.timeLabel.text = [self timeToStringWithTimeInterval:currentTime];
}
- (IBAction)touchUpInside:(UISlider *)sender {
 [self addProgressTimer];
 //计算当前slider拖动对应的播放时间
 NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentItem.duration) * sender.value;
 // seekToTime:播放跳转到当前播放时间
 [self.player seekToTime:CMTimeMakeWithSeconds(currentTime, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
 [self addShowTime];
}

四. 重播按钮和全屏播放按钮的实现

1、在定时器每秒调用的更新Slider的方法中判断当视频播放完毕之后,显示遮盖View,而重播按钮的实现,其实就是将Slider的value置为0并重新调用点击Slider松开时的方法,将当前播放时间置为0,重新隐藏遮盖View,并调用中间播放按钮开始播放。

/** 重播按钮点击 */
- (IBAction)repeatBtnClick:(UIButton *)sender {
 self.progressSlider.value = 0;
 [self touchUpInside:self.progressSlider];
 self.coverView.hidden = YES;
 [self playOrPauseBigBtnClick:self.playOrPauseBigBtn];
}

2、全屏播放的实现

全屏播放需要控制器Moda出一个全屏播放的控制器进行全屏播放,创建全屏播放控制器CLFullViewController,并使其支持左右方向的旋转,Moda出CLFullViewController控制器,并将CLAVPlayerView添加到CLFullViewController的View上并设置frame即可,当退出全屏时,dismiss掉CLFullViewController然后将CLAVPlayerView的frame设置为原来的值。
CLFullViewController中设置可以旋转和旋转方向

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

全屏播放按钮点击事件

/** 全屏按钮点击事件 */
- (IBAction)fullViewBtnClick:(UIButton *)sender {
 sender.selected = !sender.selected;
 [self videoplayViewSwitchOrientation:sender.selected];
}
/** 弹出全屏播放器 */
- (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 遅延:0.0 options:UIViewAnimationOptionLayoutSubviews アニメーション:{
    self.frame = self.fullVc.view.bounds;
   }; completion:nil];
  };
 } else {
  [self.fullVc dismissViewControllerAnimated:NO completion:^{
   [self.contrainerViewController.view addSubview:self];
   [UIView animateWithDuration:0.15 遅延:0.0 options:UIViewAnimationOptionLayoutSubviews アニメーション:{
    self.frame = CGRectMake(0, 200, self.contrainerViewController.view.bounds.size.width, self.contrainerViewController.view.bounds.size.width * 9 / 16);
   }; completion:nil];
  };
 }
}

注意:ここでは、全画面再生コントローラーを外部のコントローラーからModaで取得する必要がありますので、CLAVPlayerViewにcontrainerViewController属性を追加してコントローラーを取得します。

簡単な封装

プレイヤーの基本的な機能は既に実装されています。次に、使用がより便利になるように封装する方法を考える必要があります。実際にはほとんどの封装が完了しています。次にやるべきことは、簡単で使いやすいインターフェースを提供し、外部からプレイヤーを簡単に呼び出せるようにすることです。

1、クラスメソッドを提供してプレイヤーを迅速に作成します。

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

2、再生するビデオのリソースは外部で決定されるべきですので、urlString属性を提供し、ビデオのリソースを受け取り、setメソッドをオーバーライドして再生します。
/** 再生するビデオリソースのsetメソッド */

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

外部でプレイヤーを使用する際は非常に簡単で、内部のロジックを考慮する必要はありません。CLAVPlayerViewを迅速に作成し、コントローラーのViewに追加し、frameを設定して、プレイするビデオリソースを指定するだけで良いです。

- (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];
}

最後に、ビデオプレイヤーはこんな感じです

まとめ

多くの改善が必要な部分が多く、一部の機能も未実装です。例えば、二つの占位符のボタンは、将来的にはビデオのダウンロードやダンスのオンオフを制御するために使用できます。ビデオ再生が終わった後のシェアボタンも未実装です。将来的に実装された後、皆さんに共有し続けます。これがこの記事の全てです。この記事の内容が皆さんに役立つことを願っています。何か疑問があれば、コメントを残してください。

声明:この記事の内容はインターネットから収集され、著作権者に帰属します。インターネットユーザーが自発的に貢献し、自己でアップロードしました。このサイトは所有権を持ちません。人工的な編集は行われていません。また、関連する法的責任を負いません。著作権侵害を疑う内容がある場合は、メールを送信してください:notice#oldtoolbag.com(メール送信時、#を@に置き換えてください。報告を行い、関連する証拠を提供してください。一旦確認がついたら、このサイトは即座に侵害を疑われるコンテンツを削除します。)

基本教程
おすすめ