欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解iOS視頻播放方式

 更新時(shí)間:2017年12月12日 11:16:04   作者:Zxiao..旭  
本篇文章給大家詳細(xì)講述了詳解iOS視頻播放方式以及第三方開元播放軟件的使用,學(xué)習(xí)下吧。

多媒體這整個(gè)系列的文章自己也準(zhǔn)備好開始整理了,先從視頻音頻最簡(jiǎn)單也是最常用的播放出發(fā)慢慢的往下深究,探索到底層的編碼解碼等等,這篇文章就從視頻的播放這個(gè)最簡(jiǎn)單的說起。

iOS的視頻播放方式有幾種?其實(shí)要是只是簡(jiǎn)單的想播放一段視頻并且對(duì)UI沒什么要求的話的確比較簡(jiǎn)單,很容易搞定,但我相信這種情況除了你的Demo一般是不會(huì)出現(xiàn)的,對(duì)播放UI的定義以及可能有各種不同的需求對(duì)應(yīng)著你是不能隨便寫個(gè)播放器就沒事了的。

最原始的播放

要不是剛接觸iOS開發(fā)的同學(xué)應(yīng)該是知道MediaPlayer這個(gè)框架的,要是想簡(jiǎn)單的使用它播放視頻,可能幾行代碼就能搞定了,它里面有一個(gè)MPMoviePlayerViewController,利用起來簡(jiǎn)單的不要不要的。

不過遺憾的是自從iOS 9.0開始,它是被Apple遺棄了的,9.0之后的項(xiàng)目建議用的我們下面再說,你要是有維護(hù)9.0之前的項(xiàng)目,可能它你也有必要了解一下,我們也介紹一個(gè)它的基本的使用,以及它里面的整個(gè)播放的代碼邏輯。

工程師以前寫過一個(gè)三方,KRVideoPlayer 

這個(gè)播放器就是基于MediaPlayer框架寫的,里面就兩個(gè)文件,代碼也是相當(dāng)?shù)暮?jiǎn)單,你直接把它源碼下載下來之后我們當(dāng)一個(gè)了解MediaPlayer的Demo簡(jiǎn)單的說一下。下滿是它git上面展示的gif Demo圖片:

你在看看它源碼里面的文件:只有 KRVideoPlayerControlView 和 KRVideoPlayerController 兩個(gè),簡(jiǎn)單分析它們:

1、KRVideoPlayerControlView 繼承自 UIView

說白了這個(gè)文件寫的就是播放器的UI,包括一些播放按鈕,進(jìn)度條,以及全屏切換等等

2、KRVideoPlayerController   集成自 MPMoviePlayerController  

繼承之后直接使用MPMoviePlayerController來播放視頻,是在它初始化的時(shí)候在self.view 上添加 KRVideoPlayerControlView 這個(gè)自定義的UI,你可以看到下面的代碼:

// 初始化KRVideoPlayerController
- (instancetype)initWithFrame:(CGRect)frame
{
 self = [super init];
 if (self) {
 self.view.frame = frame;
 self.view.backgroundColor = [UIColor blackColor];
 self.controlStyle = MPMovieControlStyleNone;
 [self.view addSubview:self.videoControl];
 self.videoControl.frame = self.view.bounds;
 [self configObserver];
 [self configControlAction];
 }
 return self;
}
// 懶加載KRVideoPlayerControlView
- (KRVideoPlayerControlView *)videoControl
{
 if (!_videoControl) {
 _videoControl = [[KRVideoPlayerControlView alloc] init];
 }
 return _videoControl;
}

 

關(guān)于MediaPlayer還有下面的需要你留意一下:

1、關(guān)于播放或者暫停等的方法都是在MPMediaPlayback協(xié)議里面的

2、MPMoviePlayerController就是遵守了上面說的MPMediaPlayback協(xié)議,下面的MPMoviePlayerController源碼:

3、在給MPMoviePlayerController寫的類別MPMovieProperties、MPMoviePlayerThumbnailGeneration、MPMoviePlayerTimedMetadataAdditions包含了這個(gè)播放器幾乎所有的功能,淡然這部分的方法代代碼都是在MPMoviePlayerController.h中,有興趣或者需要的可以command進(jìn)去了解。

4、上面介紹的三方提供給大家的不僅僅是一份代碼,希望我們都能理解一個(gè)思路,就是自定義的播放器我們?cè)撛趺慈ダ斫馊?dòng)手做。這點(diǎn)后面我還會(huì)再提。

關(guān)于MediaPlayer的暫時(shí)就提這么多,有問題歡迎交流。

該升級(jí)一下了

 嗯,該升級(jí)一下了,說到這里就的說我們前面說到的9.0系統(tǒng)之后的播放器,這說這個(gè)之前順便提一個(gè)自己的見解,以前我們開發(fā)應(yīng)用的時(shí)候我記得最開始適配的最低版本是7.0以上的,到前兩年發(fā)展到8.0以上,按照我自己的理解,在11系統(tǒng)發(fā)布后我們要是做新應(yīng)用或者舊的項(xiàng)目項(xiàng)目維護(hù)的時(shí)候應(yīng)該要慢慢的舍棄7.0以及8.0的了,也就是最低版本按照9.0開始,因?yàn)椴还苁?.0還是8.0,用戶所占的比例真的是很小很下了,并且一些新鮮的功能在我們的低版本是不支持的, 維護(hù)的成本也會(huì)慢慢的變得越來越大,當(dāng)然這些也都不是空穴來風(fēng),可以上網(wǎng)去搜一下8.0之前版本系統(tǒng)占得比例,以及8.0、7.0給整個(gè)維護(hù)帶來的成本,我在最近逛一些論壇的時(shí)候也有同行在說這個(gè)問題了。好了回到正題!

說我們的正題:9.0之后Apple建議用的: AVKit框架,首先AVKit框架是8.0之后出現(xiàn)的,它是建立在我們熟悉的AVFoundation框架之上的.

利用AVKit進(jìn)行視頻播放時(shí)我們整理一下我們需要的大致都在這幾個(gè)類或者協(xié)議當(dāng)中:

1、AVPlayerItem                          (視頻要播放的元素)

2、AVPlayerLayer                        (播放顯示視頻的圖層界面)

3、AVPlayer                                (用于播放音視頻)

4、AVPlayerViewController            (控制器)

5、AVPlayerViewControllerDelegate(協(xié)議)

要是想要徹底的了解AVFoundation這個(gè)框架是不容易的,這個(gè)框架的確很龐大,有一本書叫做 《AV Foundation 開發(fā)秘籍》有興趣的可以去購(gòu)買看看,自己也在學(xué)習(xí)當(dāng)中,后續(xù)的文章全都會(huì)整理在這個(gè)系列當(dāng)中。

這篇文章就等于是給這個(gè)系列開一個(gè)頭,這個(gè)框架的學(xué)習(xí)之路應(yīng)該是漫長(zhǎng)的,也希望自己能堅(jiān)持完吧這個(gè)系列文章全都總結(jié)出來。下面把上面說的各個(gè)類分別說一下:

1、AVPlayerItem

在我們使用AVPlayer播放視頻的時(shí)候,提供視頻信息的就是AVPlayerItem,一個(gè)AVPlayerItem對(duì)應(yīng)著你提供的一個(gè)視頻Url資源,這個(gè)理解它的時(shí)候可以把它比作一個(gè)Model, 你初始化了AVPlayerItem之后,并不是馬上就可以使用它了,因?yàn)榉彩呛蚒rl網(wǎng)絡(luò)扯上關(guān)系的,都需要時(shí)間,等AVPlayerItem加載好之后就可以使用它了,那這一步我們?cè)趺刺幚砟兀?/p>

1> : 答案是利用KVO觀察statues屬性為 AVPlayerStatusReadyToPlay,看看這個(gè)屬性的定義:

 @property (nonatomic, readonly) AVPlayerStatus status  它是一個(gè)只讀屬性,這點(diǎn)也需要注意,其實(shí)也就理解利用KVO的原因。

2>: 順便總結(jié)要是你要顯示當(dāng)前視屏的緩存進(jìn)度,你需要監(jiān)測(cè)它的loadedTimeRanges屬性。

2、AVPlayerLayer

它主要負(fù)責(zé)的就是視頻的顯示,繼承自CALayer,其實(shí)你可以把它理解成我們的View。我們自定義的那些播放時(shí)候的控件就是添加在它上面的,比如我們能看到的播放按鈕,停止按鈕,或者播放進(jìn)度條等等。

3、 AVPlayer  

它主要負(fù)責(zé)的是管理視頻播放,暫停等等,相當(dāng)于一個(gè)視頻管理器,要是類比的話他就是一個(gè)ViewController(當(dāng)然不是真正的ViewController),這三者就基本含括了一個(gè)基本的視頻播,基于著三者我們總結(jié)一下播放一個(gè)視頻的基本的過程:

首先,得到視頻的URL 根據(jù)URL創(chuàng)建AVPlayerItem 把AVPlayerItem 提供給 AVPlayer AVPlayerLayer 顯示視頻。 AVPlayer 控制視頻, 播放, 暫停, 跳轉(zhuǎn) 等等。播放過程中獲取緩沖進(jìn)度,獲取播放進(jìn)度。視頻播放完成后做些什么,是暫停還是循環(huán)播放,還是獲取最后一幀圖像。

4、AVPlayerViewController

它是Apple 幫我們封裝好的可以一個(gè)視頻播放控制器,它就有一個(gè)  @property (nonatomic, strong, nullable) AVPlayer *player 的屬性,前面的AVPlayer也就像相應(yīng)的需要賦值給它,它里面還有一些我們需要理解一下的屬性,我們也把它寫出來,具體代碼我們下面再看:

player:                                    設(shè)置播放器 showsPlaybackControls:           設(shè)置是否顯示媒體播放組件,默認(rèn)YES videoGravity:                           設(shè)置視頻拉伸模式 allowsPictureInPicturePlayback: 設(shè)置是否允許畫中畫回放,默認(rèn)YES delegate:                                設(shè)置代理

5、AVPlayerViewControllerDelegate

這個(gè)代理就是前面說的AVPlayerViewController的協(xié)議,它主要的是為畫中畫的設(shè)置的代理,前面介紹 AVPlayerViewController 的時(shí)候有看到過一個(gè)是否允許畫中畫的屬性,具體什么是畫中畫相信大家都了解,看過直接的朋友應(yīng)該都看到了這個(gè)技術(shù)點(diǎn)的具體應(yīng)用。我們看看它里面的飯法規(guī)主要都干了些什么?

// 1、即將開始畫中畫
- (void)playerViewControllerWillStartPictureInPicture:(AVPlayerViewController *)playerViewController;
// 2、開始畫中畫
- (void)playerViewControllerDidStartPictureInPicture:(AVPlayerViewController *)playerViewController;
// 3、畫中畫失敗
- (void)playerViewController:(AVPlayerViewController *)playerViewController failedToStartPictureInPictureWithError:(NSError *)error;
// 4、即將結(jié)束畫中畫
- (void)playerViewControllerWillStopPictureInPicture:(AVPlayerViewController *)playerViewController;
// 5、結(jié)束畫中畫
- (void)playerViewControllerDidStopPictureInPicture:(AVPlayerViewController *)playerViewController;

 

我們看一個(gè)簡(jiǎn)單的Demo 

我們先不說關(guān)于AVFoundation復(fù)雜的東西,因?yàn)樽约阂彩窃趯W(xué)習(xí)這個(gè) AVFoundation當(dāng)中,我們先看一些很簡(jiǎn)單的Demo,就簡(jiǎn)單的利用一下AVFoundation 播放一下視頻:

我們?cè)诤?jiǎn)單的看一下我們寫的這部分的代碼,簡(jiǎn)單的先使用了一下我們說的上面的一些知識(shí)點(diǎn):

- (void)viewDidLoad {
 [super viewDidLoad];
 // Do any additional setup after loading the view.
 self.view.backgroundColor = [UIColor whiteColor]; 
 self.avPlayerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:MovieURL]];
 self.avPlayer = [[AVPlayer alloc]initWithPlayerItem:self.avPlayerItem];
 self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
 self.avPlayerLayer.frame = CGRectMake(10, 100, 355, 200);
 [self.view.layer addSublayer:self.avPlayerLayer];
 // 添加觀察者
 [self addObserverWithAVPlayerItem];
}
#pragma mark --
#pragma mark -- KVO
-(void)addObserverWithAVPlayerItem{
 //狀態(tài)添加觀察者
 [self.avPlayerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
 // 緩存進(jìn)度添加觀察者
 [self.avPlayerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
 AVPlayerItem * avplayeritem = (AVPlayerItem *)object;
 if ([keyPath isEqualToString:@"status"]) {
 AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
 if (status == AVPlayerStatusReadyToPlay) {
  NSLog(@"準(zhǔn)備好播放");
  CMTime duration = avplayeritem.duration;
  NSLog(@"視頻總時(shí)長(zhǎng):%.2f",CMTimeGetSeconds(duration));
  // 播放
  [self.avPlayer play];
 }else if (status == AVPlayerStatusFailed){
  NSLog(@"視頻準(zhǔn)備發(fā)生錯(cuò)誤");
 }else{
  NSLog(@"位置錯(cuò)誤");
 }
 }else if ([keyPath isEqualToString:@"loadedTimeRanges"]){
  // 可以自定義緩存進(jìn)度
  NSTimeInterval timeInterval = [self alreadyCacheVideoProgress];
  NSLog(@"視頻已經(jīng)緩存的時(shí)長(zhǎng):%.2f",timeInterval);
 }
}

#pragma mark --
#pragma mark -- alreadyCacheVideoProgress
-(NSTimeInterval)alreadyCacheVideoProgress{
 
 // 先獲取到它的緩存的進(jìn)度
 NSArray * cacheVideoTime = [self.avPlayerItem loadedTimeRanges];
 // CMTimeRange 結(jié)構(gòu)體 start duration 表示起始位置 和 持續(xù)時(shí)間
 // 獲取緩沖區(qū)域
 CMTimeRange timeRange = [cacheVideoTime.firstObject CMTimeRangeValue];
 float startSeconds = CMTimeGetSeconds(timeRange.start);
 float durationSeconds = CMTimeGetSeconds(timeRange.duration);
 // 計(jì)算總緩沖時(shí)間 = start + duration
 NSTimeInterval result = startSeconds + durationSeconds;
 return result;
} 

這些點(diǎn)我們有必要注意一下

1、CMTime  一個(gè)專門用于標(biāo)識(shí)視頻時(shí)間的結(jié)構(gòu)體

/*!
	@typedef	CMTime
	@abstract	Rational time value represented as int64/int32.
*/
typedef struct
{
	CMTimeValue	value;		/*! @field value The value of the CMTime. value/timescale = seconds. 幀數(shù) */
	CMTimeScale	timescale;	/*! @field timescale The timescale of the CMTime. value/timescale = seconds.幀率(影片每秒有幾幀)*/ CMTimeFlags flags; /*! @field flags The flags, eg. kCMTimeFlags_Valid, kCMTimeFlags_PositiveInfinity, etc. */  CMTimeEpoch epoch; /*! @field epoch Differentiates between equal timestamps that are actually different because of looping, multi-item sequencing, etc. Will be used during comparison: greater epochs happen after lesser ones. Additions/subtraction is only possible within a single epoch, however, since epoch length may be unknown/variable. */} CMTime;

前面的代碼中我們看到有一個(gè)獲取視頻總長(zhǎng)度的方法:

CMTime duration = avplayeritem.duration;
NSLog(@"視頻總時(shí)長(zhǎng):%.2f",CMTimeGetSeconds(duration));

可以看到CMTimeGetSeconds這個(gè)函數(shù)把一個(gè)CMTime類型轉(zhuǎn)化成一個(gè)浮點(diǎn)型,如果一個(gè)影片為60幀/每秒, 當(dāng)前想要跳轉(zhuǎn)到120幀的位置,也就是兩秒的位置,那么就可以創(chuàng)建一個(gè) CMTime 類型數(shù)據(jù)。它通??梢杂孟旅鎯蓚€(gè)函數(shù)來創(chuàng)建.

1>: CMTimeMake(int64_t value, int32_t scale)                          Eg: CMTime time1 = CMTimeMake(120, 60);

2>:CMTimeMakeWithSeconds(Flout64 seconds, int32_t scale)   Eg: CMTime time2 = CMTimeWithSeconds(120, 60);

CMTimeMakeWithSeconds 和 CMTimeMake 區(qū)別在于,第一個(gè)函數(shù)的第一個(gè)參數(shù)可以是float,其他一樣。

- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;

比如說:我們把時(shí)間間隔設(shè)置為, 1/ 10 秒,然后 block 里面更新 UI。就是一秒鐘更新10次UI,我們驗(yàn)證一下:

[self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 10) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
  // CMTime的timescale的定義幫助理解下面代碼
  // @field timescale The timescale of the CMTime. value/timescale = seconds.
  float currentPlayTime = (double)self.avPlayerItem.currentTime.value/ self.avPlayerItem.currentTime.timescale;
  NSLog(@"當(dāng)前播放進(jìn)度:%f",currentPlayTime);
 }];

我們隨便截取出一段打印的日志,看一下結(jié)果就可以驗(yàn)證:

2、AVPlayerItem  視頻播放結(jié)束通知

/* Note that NSNotifications posted by AVPlayerItem may be posted on a different thread from the one on which the observer was registered. */

// notifications          description
AVF_EXPORT NSString *const AVPlayerItemTimeJumpedNotification			 NS_AVAILABLE(10_7, 5_0);	// the item's current time has changed discontinuously
AVF_EXPORT NSString *const AVPlayerItemDidPlayToEndTimeNotification NS_AVAILABLE(10_7, 4_0); // item has played to its end time
AVF_EXPORT NSString *const AVPlayerItemFailedToPlayToEndTimeNotification NS_AVAILABLE(10_7, 4_3); // item has failed to play to its end time
AVF_EXPORT NSString *const AVPlayerItemPlaybackStalledNotification NS_AVAILABLE(10_9, 6_0); // media did not arrive in time to continue playback
AVF_EXPORT NSString *const AVPlayerItemNewAccessLogEntryNotification	 NS_AVAILABLE(10_9, 6_0);	// a new access log entry has been added
AVF_EXPORT NSString *const AVPlayerItemNewErrorLogEntryNotification		 NS_AVAILABLE(10_9, 6_0);	// a new error log entry has been added

// notification userInfo key         type
AVF_EXPORT NSString *const AVPlayerItemFailedToPlayToEndTimeErrorKey NS_AVAILABLE(10_7, 4_3); // NSError

3、這些個(gè)三方框架

(1): VKVideoPlayer

(2): ALMoviePlayerController

(3): PBJVideoPlayer

(4): 還有這個(gè)比較厲害的MobileVLCKit

關(guān)于上面上的這些三方都給出了連接,最后一個(gè)給的是一篇幫助我們集成的文章,這些三方在后面這個(gè)系列文章的總結(jié)中會(huì)一點(diǎn)點(diǎn)慢慢的全都說一下,在這里只提一下有這些框架在,有興趣可以先了解,后面我在總結(jié)。

相關(guān)文章

  • iOS的UI開發(fā)中Button的基本編寫方法講解

    iOS的UI開發(fā)中Button的基本編寫方法講解

    這篇文章主要介紹了iOS的UI開發(fā)中Button的基本編寫方法講解,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下
    2015-11-11
  • 一行iOS代碼實(shí)現(xiàn)圖片無限輪播器

    一行iOS代碼實(shí)現(xiàn)圖片無限輪播器

    一行iOS代碼實(shí)現(xiàn)圖片無限輪播器的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 詳解IOS 利用storyboard修改UITextField的placeholder文字顏色

    詳解IOS 利用storyboard修改UITextField的placeholder文字顏色

    這篇文章主要介紹了詳解IOS 利用storyboard修改UITextField的placeholder文字顏色的相關(guān)資料,希望通過本文能實(shí)現(xiàn)這樣類似的功能,需要的朋友可以參考下
    2017-08-08
  • iOS開發(fā)實(shí)現(xiàn)轉(zhuǎn)盤功能

    iOS開發(fā)實(shí)現(xiàn)轉(zhuǎn)盤功能

    這篇文章主要為大家詳細(xì)介紹了iOS開發(fā)實(shí)現(xiàn)轉(zhuǎn)盤功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • IOS利用CocoaHttpServer搭建手機(jī)本地服務(wù)器

    IOS利用CocoaHttpServer搭建手機(jī)本地服務(wù)器

    這篇文章主要介紹了IOS利用CocoaHttpServer搭建手機(jī)本地服務(wù)器的步驟,幫助大家更好的理解和學(xué)習(xí)使用ios開發(fā),感興趣的朋友可以了解下
    2021-04-04
  • iOS鍵盤如何添加隱藏鍵盤功能

    iOS鍵盤如何添加隱藏鍵盤功能

    這篇文章主要為大家詳細(xì)介紹了iOS鍵盤如何添加隱藏鍵盤功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • IOS 圖文混排(CoreText.framework)詳解及實(shí)例

    IOS 圖文混排(CoreText.framework)詳解及實(shí)例

    這篇文章主要介紹了IOS 圖文混排(CoreText.framework)詳解及實(shí)例的相關(guān)資料,這里對(duì)IOS 的圖文混排進(jìn)行了詳細(xì)介紹,并附代碼實(shí)例,和實(shí)現(xiàn)效果圖,需要的朋友可以參考下
    2016-11-11
  • iOS實(shí)現(xiàn)比例拼圖的方法示例

    iOS實(shí)現(xiàn)比例拼圖的方法示例

    這篇文章主要給大家介紹了關(guān)于iOS實(shí)現(xiàn)比例拼圖的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者開發(fā)iOS具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • IOS 開發(fā)之swift中UIView的擴(kuò)展使用的實(shí)例

    IOS 開發(fā)之swift中UIView的擴(kuò)展使用的實(shí)例

    這篇文章主要介紹了IOS 開發(fā)之swift中UIView的擴(kuò)展使用的實(shí)例的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • iOS 導(dǎo)航欄自帶頁(yè)面右滑pop使用示例

    iOS 導(dǎo)航欄自帶頁(yè)面右滑pop使用示例

    本篇文章主要介紹了iOS 導(dǎo)航欄自帶頁(yè)面右滑pop使用示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12

最新評(píng)論