日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

用AVPlayer播放视频

發(fā)布時間:2023/12/31 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用AVPlayer播放视频 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

控制assets的播放,你可以使用AVPlayer對象。在播放的過程中,你可以使用AVPlayerItem對象來管理asset的呈現(xiàn),AVPlayerItemTrack來管理track。要顯示視頻,需要使用AVPlayerLayer。

播放Assets

一個播放器就是控制asset播放的對象,比如開始和結(jié)束,seek到指定的時間。可以使用AVPlayer來播放單個asset,用AVQueuePlayer來播放多個連續(xù)的asset。一個player向你提供播放的信息,如果需要,你通過player的狀態(tài)同步顯示到界面上。你也可以直接把player的輸出顯示笑傲指定的動畫層(AVPlayerLayer或者AVSynchronizedLayer),想知道更多關(guān)于layer的信息,請查看Core Animation Programming Guide

多個layer的情況:你可以創(chuàng)建多個AVPlayerLayer對象,但是只有最近創(chuàng)建的layer才會顯示視頻畫面。

雖然是播放asset,但是不能直接把asset傳給AVPlayer對象,你應(yīng)該提供AVPlayerItem對象給AVPlayer。一個player item管理著和它相關(guān)的asset。一個player item包括player item tracks-(AVPlayerItemTrack對象,表示asset中的tracks)。他們之間的關(guān)系如下圖:

這表明你可以同時用不同的player播放同一個asset,如下圖顯示,兩個不同的player播放同一個asset。

你可以用一個存在asset直接初始化player,或者直接用URL初始化。和AVAsset一樣,簡單的初始化一個player并不表示可以馬上進(jìn)行播放,你需要觀察它的status(通過kvo)來決定是否可以播放。

處理不同類型的asset

配置asset的方式由需要播放的asset的類型決定的。概括的說,有兩種方式:基于文件的asset,基于流式的(http live streaming format)

加載基于文件的asset,有如下幾步:

· 使用AVURLAsset創(chuàng)建一個asset。

· 使用創(chuàng)建的asset來創(chuàng)建一個AVPlayerItem對象item

· item和AVPlayer關(guān)聯(lián)

· 等待item的狀態(tài),知道可以播放。

創(chuàng)建基于HTTP live stream的播放器。

用url初始化一個AVPlayerItem對象。(http live stream的情況下不能直接創(chuàng)建AVAsset對象)

NSURL *url = [NSURL URLWithString:@"<#Live stream URL#>]; // You may find a test stream at <http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8>. self.playerItem = [AVPlayerItem playerItemWithURL:url]; [playerItem addObserver:self forKeyPath:@"status" options:0 context:&ItemStatusContext]; self.player = [AVPlayer playerWithPlayerItem:playerItem];

當(dāng)你關(guān)聯(lián)一個player item到player的時候,這個播放器開始準(zhǔn)備播放。當(dāng)它可以播放的時候,player item會創(chuàng)建AVAsset和AVAssetTrack對象,這些對象可以用來檢查live stream的內(nèi)容。為了獲取stream的時間,可以通過kvo的方式觀察player item的duration的屬性。當(dāng)可以播放的時候,這個屬性被設(shè)置為正確的值,這時就可以獲取時間。

注意:只能在iOS4.3之后使用player item的duration屬性。下面這種獲取duration的方法適用于所有的iOS系統(tǒng)版本:當(dāng)player item的狀態(tài)變?yōu)?span id="ozvdkddzhkzd" class="hljs-built_in">AVPlayerItemStatusReadyToPlay時,duration可以通過下面代碼獲取 [[[[[playerItem tracks] objectAtIndex:0] assetTrack] asset] duration];

如果僅僅是想播放一個live stream,可以直接用下面的簡短代碼實現(xiàn):

self.player = [AVPlayer playerWithURL:<#Live stream URL#>]; [player addObserver:self forKeyPath:@"status" options:0 context:&PlayerStatusContext];

正如assets和items一樣,初始化一個player之后并不表明可以馬上播放,你需要觀察player的status屬性,當(dāng)status變?yōu)锳VPlayerStatusReadyToPlay時表示可以播放了,你也需要觀察curretItem屬性來訪問player item。

如果你不能確定你用的url是什么類型,可以用下面的方法檢測:1、嘗試用url初始化AVURLAsset,然后load它的tracks key,如果tracks load 成功,表明你可以用這個asset創(chuàng)建player item。2、如果第一步失敗,直接用url創(chuàng)建AVPlayerItem,觀察status屬性,看是否有可播放的狀態(tài)。

播放一個item

如果想要播放,你可以想player發(fā)送play消息,如下代碼:

- (IBAction)play:sender { [player play]; }

除了播放之外,還可以管理player的各種信息,比如rate和播放頭,你也可以監(jiān)控player的狀態(tài),這很有用,比如說你需要根據(jù)播放的狀態(tài)來更新界面。

改變播放的rate

可以改變播放的rate,代碼如下:

aPlayer.rate = 0.5; aPlayer.rate = 2.0;

rate=1.0表示正常的播放。0.0表示暫停。player item支持逆向播放,當(dāng)rate設(shè)置為負(fù)數(shù)的時候就是逆向播放.playeritem的 canPlayReverse 表示rate為-1.0,canPlaySlowReverse表示rate的范圍是-0.0到-1.0,canPlayFastReverse表示rate小于-1.0f。

seeking-重定位播放頭

可以使用seekToTime:重定位播放頭到指定的時間,如下代碼:

CMTime fiveSecondsIn = CMTimeMake(5, 1); [player seekToTime:fiveSecondsIn];

seekTime:不能精確定位,如果需要精確定位,可以使用seekToTime:toleranceBefore:toleranceAfter:,代碼如下:

CMTime fiveSecondsIn = CMTimeMake(5, 1); [player seekToTime:fiveSecondsIn toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];

當(dāng)tolerance=0的時候,framework需要進(jìn)行大量解碼工作,比較耗性能,所以,只有當(dāng)你必須使用的時候才用這個方法,比如開發(fā)一個復(fù)雜的多媒體編輯應(yīng)用,這需要精確的控制。

當(dāng)播放結(jié)束后,播放頭移動到playerItem的末尾,如果此時調(diào)用play方法是沒有效果的,應(yīng)該先把播放頭移到player item起始位置。如果需要實現(xiàn)循環(huán)播放的功能,可以監(jiān)聽通知AVPlayerItemDidPlayToEndTimeNotification,當(dāng)收到這個通知的時候,調(diào)用seekToTime:把播放頭移動到起始位置,代碼如下:

// Register with the notification center after creating the player item.[[NSNotificationCenter defaultCenter]addObserver:selfselector:@selector(playerItemDidReachEnd:)name:AVPlayerItemDidPlayToEndTimeNotificationobject:<#The player item#>];- (void)playerItemDidReachEnd:(NSNotification *)notification {[player seekToTime:kCMTimeZero]; }

播放多個items

可以使用AVQueuePlayer播放多個items,AVQueuePlayer是AVPlayer的子類,可以用一個數(shù)組來初始化一個AVQueuePlayer對象。代碼如下:

NSArray *items = <#An array of player items#>; AVQueuePlayer *queuePlayer = [[AVQueuePlayer alloc] initWithItems:items];

和AVPlayer一樣,直接調(diào)用play方法來播放,queue player順序播放隊列中的item,如果想要跳過一個item,播放下一個item,可以調(diào)用方法advanceToNextItem。

可以對隊列進(jìn)行插入和刪除操作,調(diào)用方法insertItem:afterItem:, removeItem:, 和 removeAllItems。正常情況下當(dāng)插入一個item之前,應(yīng)該檢查是否可以插入,通過使用canInsertItem:afterItem:方法,第二個參數(shù)傳nil,代碼如下:

AVPlayerItem *anItem = <#Get a player item#>; if ([queuePlayer canInsertItem:anItem afterItem:nil]) {[queuePlayer insertItem:anItem afterItem:nil]; }

監(jiān)測播放狀態(tài)

可以監(jiān)測player和player item的狀態(tài),這個非常有用。比如:
· 如果用戶切換到其他應(yīng)用程序,則需要把player的rate設(shè)為0.0
· 如果播放的是遠(yuǎn)程媒體,當(dāng)收到更多的數(shù)據(jù)的時候,player的loadedTimeRange和seekableTimeRange屬性將會不斷改變。
· 當(dāng)player播放的是http live stream的時候,player的currentItem會不斷改變。
· 播放http live stream的時候,player item的tracks屬性也不斷改變。這會發(fā)生在player改變編碼方式的時候。
· 當(dāng)播放失敗的時候,player或者player item的status屬性也會改變。

可以使用kvo來監(jiān)測上述改變。

注意:只能在主線程注冊和取消kvo

status改變后的處理方式

當(dāng)player或者player item的狀態(tài)status改變,系統(tǒng)會發(fā)送一個kvo的notification,如果一個對象由于一些原因不能播放,stauts會變成AVPlayerStatusFailed 或者 AVPlayerItemStatusFailed ,在這種情況下,這個對象的error屬性會被附上一個error類型的對象,這個error對象描述了失敗的原因。

AV Foundation不會指定這個notification是由哪個線程發(fā)出的,所以,如果你要更新UI,就必須確保更新的代碼在主線程中調(diào)用,下面的代碼表示收到status更新的處理方式:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)objectchange:(NSDictionary *)change context:(void *)context {if (context == <#Player status context#>) {AVPlayer *thePlayer = (AVPlayer *)object;if ([thePlayer status] == AVPlayerStatusFailed) {NSError *error = [<#The AVPlayer object#> error];// Respond to error: for example, display an alert sheet.return;}// Deal with other status change if appropriate.}// Deal with other change notifications if appropriate.[super observeValueForKeyPath:keyPath ofObject:objectchange:change context:context];return; }

監(jiān)聽視頻準(zhǔn)備播放的狀態(tài)

可以監(jiān)聽AVPlayerLayer的readyForDisplay屬性,當(dāng)layer有可顯示的內(nèi)容時,會發(fā)送一個notification。

跟蹤時間

可以使用addPeriodicTimeObserverForInterval:queue:usingBlock: 或者 addBoundaryTimeObserverForTimes:queue:usingBlock:來跟蹤播放的進(jìn)度,根據(jù)這個進(jìn)度,你可以更新UI,比如播放了多少時間,還剩多少時間,或者其他的UI狀態(tài)。
· addPeriodicTimeObserverForInterval:queue:usingBlock:,這個方法傳入一個CMTime結(jié)構(gòu)的時間區(qū)間,每隔這個時間段的時候,block會回調(diào)一次,開始和結(jié)束播放的時候block也會回調(diào)一次。
· addBoundaryTimeObserverForTimes:queue:usingBlock:,這個放傳入一個CMTime結(jié)構(gòu)的數(shù)組,當(dāng)播放到數(shù)組里面的時間點的時候,block會回調(diào)。
這兩個方法都返回一個id類型的對象,這個對象必須一直被持有。可以使用removeTimeObserver:取消這個觀察者。

對于這兩個方法,AVFoundation不會保證每次時間點到了的時候都會回調(diào)block,如果前面回調(diào)的block沒有執(zhí)行完的時候,下一次就不會回調(diào)。所以,必須保證在block里面的邏輯不能太耗時。下面是使用的例子:

// Assume a property: @property (strong) id playerObserver; Float64 durationSeconds = CMTimeGetSeconds([<#An asset#> duration]); CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/3.0, 1); CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*2.0/3.0, 1); NSArray *times = @[[NSValue valueWithCMTime:firstThird], [NSValue valueWithCMTime:secondThird]];self.playerObserver = [<#A player#> addBoundaryTimeObserverForTimes:times queue:NULL usingBlock:^{NSString *timeDescription = (NSString *)CFBridgingRelease(CMTimeCopyDescription(NULL, [self.player currentTime]));NSLog(@"Passed a boundary at %@", timeDescription); }];

播放結(jié)束

可以向通知中心注冊 AVPlayerItemDidPlayToEndTimeNotification 通知,當(dāng)播放結(jié)束的時候可以收到一個結(jié)束的通知。代碼:

[[NSNotificationCenter defaultCenter] addObserver:<#The observer, typically self#>selector:@selector(<#The selector name#>)name:AVPlayerItemDidPlayToEndTimeNotificationobject:<#A player item#>];

完整的例子:用AVPlayerLayer播放一個video

下面的代碼向你展示如何使用AVPLayer播放一個video文件,步驟如下:
1、用AVPlayerLayer配置一個view
2、創(chuàng)建一個AVPlayer
3、用video文件創(chuàng)建一個AVPlayerItem對象,并且用kvo觀察他的status
4、 當(dāng)收到item的狀態(tài)變成可播放的時候,播放按鈕啟用
5、 播放,結(jié)束之后把播放頭設(shè)置到起始位置

player view

為了播放一個視頻,需要個view,這個view的layer是AVPlayerLayer對象。可以創(chuàng)建一個子類實現(xiàn)這個需求。代碼:

#import <UIKit/UIKit.h> #import <AVFoundation/AVFoundation.h> @interface PlayerView : UIView @property (nonatomic) AVPlayer *player; @end@implementation PlayerView + (Class)layerClass {return [AVPlayerLayer class]; } - (AVPlayer*)player {return [(AVPlayerLayer *)[self layer] player]; } - (void)setPlayer:(AVPlayer *)player {[(AVPlayerLayer *)[self layer] setPlayer:player]; } @end

View controller

同時你需要一個view controller,代碼如下:

@class PlayerView; @interface PlayerViewController : UIViewController@property (nonatomic) AVPlayer *player; @property (nonatomic) AVPlayerItem *playerItem; @property (nonatomic, weak) IBOutlet PlayerView *playerView; @property (nonatomic, weak) IBOutlet UIButton *playButton; - (IBAction)loadAssetFromFile:sender; - (IBAction)play:sender; - (void)syncUI; @end

syncUI方法的作用是根據(jù)player的status來更新播放按鈕,實現(xiàn)如下:

- (void)syncUI {if ((self.player.currentItem != nil) &&([self.player.currentItem status] == AVPlayerItemStatusReadyToPlay)) {self.playButton.enabled = YES;}else {self.playButton.enabled = NO;} }

在viewdidload里面調(diào)用syncUI,確保剛開始顯示的頁面的時候按鈕是不可用的。代碼如下:

- (void)viewDidLoad {[super viewDidLoad];[self syncUI]; }

其他的屬性和方法在接下來的文字說明。

創(chuàng)建一個asset

通過URL創(chuàng)建一個AVURLAsset對象。代碼如下:

- (IBAction)loadAssetFromFile:sender {NSURL *fileURL = [[NSBundle mainBundle]URLForResource:<#@"VideoFileName"#> withExtension:<#@"extension"#>];AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];NSString *tracksKey = @"tracks";[asset loadValuesAsynchronouslyForKeys:@[tracksKey] completionHandler:^{// The completion block goes here.}]; }

在完成的block里面,用asset創(chuàng)建一個AVPlayerItem對象和一個AVPlayer對象,并且把player設(shè)為player view的屬性。和創(chuàng)建一個asset一樣,簡單的創(chuàng)建一個player item并不意味著可以馬上使用,可以用kvo觀察player item 的status來判斷是否可以開始播放,這個kvo的設(shè)置應(yīng)該在player item和player關(guān)聯(lián)之前設(shè)置。代碼如下:

// Define this constant for the key-value observation context. static const NSString *ItemStatusContext;// Completion handler block.dispatch_async(dispatch_get_main_queue(),^{NSError *error;AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey error:&error];if (status == AVKeyValueStatusLoaded) {self.playerItem = [AVPlayerItem playerItemWithAsset:asset];// ensure that this is done before the playerItem is associated with the player[self.playerItem addObserver:self forKeyPath:@"status"options:NSKeyValueObservingOptionInitial context:&ItemStatusContext];[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(playerItemDidReachEnd:)name:AVPlayerItemDidPlayToEndTimeNotificationobject:self.playerItem];self.player = [AVPlayer playerWithPlayerItem:self.playerItem];[self.playerView setPlayer:self.player];}else {// You should deal with the error appropriately.NSLog(@"The asset's tracks were not loaded:\n%@", [error localizedDescription]);}});

player item的status改變時的處理

當(dāng)player item的status改變時,view controller會收到一個通知消息,AVFoundation并不指定這個消息是由哪個線程發(fā)出的。如果你要更新ui,必須確保更新ui的代碼在主線程中。下面的代碼顯示更新ui的邏輯:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)objectchange:(NSDictionary *)change context:(void *)context {if (context == &ItemStatusContext) {dispatch_async(dispatch_get_main_queue(),^{[self syncUI];});return;}[super observeValueForKeyPath:keyPath ofObject:objectchange:change context:context];return; }

播放

播放很簡單,直接向player發(fā)送play消息即可。代碼如下:

- (IBAction)play:sender { [player play]; }

這樣的情況只能播放一次,當(dāng)播放結(jié)束的時候,再調(diào)用play方法是沒有效果的,如果你要重新播放,需要向通知中心注冊AVPlayerItemDidPlayToEndTimeNotification消息,當(dāng)收到播放結(jié)束的消息的時候,調(diào)用seekToTime:把播放頭移動到起始位置,這樣再調(diào)用play的時候就可以重新播放了。代碼如下:

// Register with the notification center after creating the player item.[[NSNotificationCenter defaultCenter]addObserver:selfselector:@selector(playerItemDidReachEnd:)name:AVPlayerItemDidPlayToEndTimeNotificationobject:[self.player currentItem]];- (void)playerItemDidReachEnd:(NSNotification *)notification {[self.player seekToTime:kCMTimeZero]; }

總結(jié)

以上是生活随笔為你收集整理的用AVPlayer播放视频的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。