文章目錄
- 1. Playback - 播放
Playback - 播放
To control the playback of assets, you use an AVPlayer object. During playback, you can use an AVPlayerItem instance to manage the presentation state of an asset as a whole, and an AVPlayerItemTrack object to manage the presentation state of an individual track. To display video, you use an AVPlayerLayer object.
使用 AVPlayer 對象控制資產的播放。在播放期間,可以使用一個 AVPlayerItem 實例去管理資產作為一個整體的顯示狀態(tài),AVPlayerItemTrack 對象來管理一個單獨軌道的顯示狀態(tài)。使用 AVPlayerLayer 顯示視頻。
Playing Assets - 播放資產
A player is a controller object that you use to manage playback of an asset, for example starting and stopping playback, and seeking to a particular time. You use an instance of AVPlayer to play a single asset. You can use an AVQueuePlayer object to play a number of items in sequence (AVQueuePlayer is a subclass of AVPlayer). On OS X you have the option of the using the AVKit framework’s AVPlayerView class to play the content back within a view.
播放器是一個控制器對象,使用這個控制器對象去管理一個資產的播放,例如開始和停止播放,并且追蹤一個特定的時間。使用 AVPlayer 的實例去播放單個資產??梢允褂?AVQueuePlayer 對象去播放在一些在隊列的項目(AVQueuePlayer 是 AVPlayer 的子類)。在 OS X 系統(tǒng)中,可以選擇使用 AVKit 框架的 AVPlayerView 類去播放一個視圖的內容。
A player provides you with information about the state of the playback so, if you need to, you can synchronize your user interface with the player’s state. You typically direct the output of a player to a specialized Core Animation layer (an instance of AVPlayerLayer or AVSynchronizedLayer). To learn more about layers, see Core Animation Programming Guide.
播放器提供了關于播放狀態(tài)的信息,因此如果需要,可以將用戶界面與播放器的狀態(tài)同步。通常將播放器的輸出指向專門的動畫核心層(AVPlayerLayer 或者 AVSynchronizedLayer 的一個實例)。想要了解更多關于 layers,請看 Core Animation Programming Guide。
Multiple player layers: You can create many AVPlayerLayer objects from a single AVPlayer instance, but only the most recently created such layer will display any video content onscreen.
多個播放器層:可以從一個單獨的
AVPlayer實例創(chuàng)建許多AVPlayerLayer對象,但是只有最近被創(chuàng)建的那一層將會屏幕上顯示視頻的內容。
Although ultimately you want to play an asset, you don’t provide assets directly to an AVPlayer object. Instead, you provide an instance of AVPlayerItem. A player item manages the presentation state of an asset with which it is associated. A player item contains player item tracks—instances of AVPlayerItemTrack—that correspond to the tracks in the asset. The relationship between the various objects is shown in Figure 2-1.
雖然最終想要播放一個資產,但又沒有直接給提供資產一個 AVPlayer 對象。相反,提供一個 AVPlayerItem 的實例。一個 player item 管理與它相關的資產的顯示狀態(tài)。一個player item包含了播放器項目軌道 – AVPlayerItemTrack—that 的實例,對應資產內的軌道。各個對象之間的關系如圖2-1所示。
This abstraction means that you can play a given asset using different players simultaneously, but rendered in different ways by each player. Figure 2-2 shows one possibility, with two different players playing the same asset, with different settings. Using the item tracks, you can, for example, disable a particular track during playback (for example, you might not want to play the sound component).
這個摘要意味著可以同時使用不同的播放器播放一個給定的資產,但每個播放器都以不同的方式呈現。圖2-2顯示了一種可能性,同一個資產有兩個不同的播放器,并且有不同的設定??梢允褂貌煌捻椖寇壍?,在播放期間禁用一個特定的軌道(例如,你可能不想播放這個聲音組件)。
You can initialize a player item with an existing asset, or you can initialize a player item directly from a URL so that you can play a resource at a particular location (AVPlayerItem will then create and configure an asset for the resource). As with AVAsset, though, simply initializing a player item doesn’t necessarily mean it’s ready for immediate playback. You can observe (using key-value observing) an item’s status property to determine if and when it’s ready to play.
可以用現有的資產初始化一個播放器項目,或者可以直接從一個 URL 初始化播放器項目,為了可以在一個特定位置播放一個資源(AVPlayerItem 將為資源創(chuàng)建和配置資產)。即使帶著 AVAsset 簡單地初始化一個播放器項目并不一定意味著它已經準備可以立即播放了??梢杂^察(使用 key-value observing])一個項目的 status 屬性,以確定是否可以播放并且當已經準備好去播放。
Handling Different Types of Asset - 處理不同類型的資產
The way you configure an asset for playback may depend on the sort of asset you want to play. Broadly speaking, there are two main types: file-based assets, to which you have random access (such as from a local file, the camera roll, or the Media Library), and stream-based assets (HTTP Live Streaming format).
配置一個準備播放的資產的方法可能取決于你想播放的資產的順序。概括地說,主要由兩種類型:基于文件的資產,可以隨機訪問(例如從一個本地文件,相機膠卷,或者媒體庫),和基于流的資產(HTTP直播流媒體格式)。
To load and play a file-based asset. There are several steps to playing a file-based asset:
- Create an asset using AVURLAsset.
- Create an instance of AVPlayerItem using the asset.
- Associate the item with an instance of AVPlayer.
- Wait until the item’s status property indicates that it’s ready to play (typically you use key-value observing to receive a notification when the status changes).
This approach is illustrated in Putting It All Together: Playing a Video File Using AVPlayerLayer.
To create and prepare an HTTP live stream for playback. Initialize an instance of AVPlayerItem using the URL. (You cannot directly create an AVAsset instance to represent the media in an HTTP Live Stream.)
加載和播放一個基于文件的資產,播放基于文件的資產有幾個步驟:
- 使用 AVURLAsset 創(chuàng)建一個資產
- 使用資產創(chuàng)建一個
AVPlayerItem的實例 - 將
AVPlayer的實例與項目聯結 - 等待,直到項目的
status屬性表明已經準備好播放了(通常當狀態(tài)改變時,使用 key-value observing 接受通知)
該方法的說明都在:Putting It All Together: Playing a Video File Using AVPlayerLayer
創(chuàng)建和編寫能夠播放的HTTP直播流媒體。使用 URL 初始化一個 AVPlayerItem 的實例。(你不能直接創(chuàng)建一個 AVAsset 的實例去代表媒體在HTTP直播流中)
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];
When you associate the player item with a player, it starts to become ready to play. When it is ready to play, the player item creates the AVAsset and AVAssetTrack instances, which you can use to inspect the contents of the live stream.
To get the duration of a streaming item, you can observe the duration property on the player item. When the item becomes ready to play, this property updates to the correct value for the stream.
當你把播放項目和播放器聯結起來時,它開始準備播放。當它準備播放時,播放項目創(chuàng)建 AVAsset 和 AVAssetTrack 實例,可以用它來檢查直播流的內容。
獲取一個流項目的持續(xù)時間,可以觀察播放項目的 duration 屬性。當項目準備就緒時,這個屬性更新為流的正確值。
Note: Using the duration property on the player item requires iOS 4.3 or later. An approach that is compatible with all versions of iOS involves observing the status property of the player item. When the status becomes AVPlayerItemStatusReadyToPlay, the duration can be fetched with the following line of code:
注意:在播放項目里使用
duration屬性要求iOS4.3,或者更高的版本。一種方法是所有版本的iOS兼容包括播放項目的 status 屬性。當status變成 AVPlayerItemStatusReadyToPlay,持續(xù)時間可以被下面的代碼獲取到:
[[[[[playerItem tracks] objectAtIndex:0] assetTrack] asset] duration];
If you simply want to play a live stream, you can take a shortcut and create a player directly using the URL use the following code:
如果你只是想播放一個直播流,你可以采取一種快捷方式,并使用 URL 直接創(chuàng)建一個播放器,代碼如下:
self.player = [AVPlayer playerWithURL:<#Live stream URL#>];
[player addObserver:self forKeyPath:@"status" options:0 context:&PlayerStatusContext];
As with assets and items, initializing the player does not mean it’s ready for playback. You should observe the player’s status property, which changes to AVPlayerStatusReadyToPlay when it is ready to play. You can also observe the currentItem property to access the player item created for the stream.
作為資產和項目,初始化播放器并不意味著它已經準備就緒可以播放。你應該觀察播放器的 status 屬性,當準備就緒的時候改變 AVPlayerStatusReadyToPlay 。也可以觀察 currentItem 屬性去訪問被流所創(chuàng)建播放項目。
If you don’t know what kind of URL you have, follow these steps:
- Try to initialize an AVURLAsset using the URL, then load its tracks key.
If the tracks load successfully, then you create a player item for the asset. - If 1 fails, create an AVPlayerItem directly from the URL.
Observe the player’s status property to determine whether it becomes playable.
If either route succeeds, you end up with a player item that you can then associate with a player.
如果你不知道現有的 URL 是什么類型的,按照下面步驟:
- 嘗試用
URL初始化一個AVURLAsset,然后將其加載為軌道的key。 - 如果上一步失敗,直接從
URL創(chuàng)建一個AVPlayerItem。觀察這個播放器的 status 屬性來決定它是否是可播放的。
如果兩個都可以成功,你最終用可以聯結給一個播放器的播放項目。
Playing an Item - 播放一個項目
To start playback, you send a play message to the player.
發(fā)送一個播放消息給播放器,開始播放:
- (IBAction)play:sender {
[player play];
}
In addition to simply playing, you can manage various aspects of the playback, such as the rate and the location of the playhead. You can also monitor the play state of the player; this is useful if you want to, for example, synchronize the user interface to the presentation state of the asset—see Monitoring Playback.
除了簡單的播放,可以管理播放的各個方面,如速度和播放頭的位置。也可以監(jiān)視播放器的播放狀態(tài);這是很有用的,例如如果你想將用戶界面同步到資產的呈現狀態(tài) – 詳情看:Monitoring Playback.
Changing the Playback Rate - 改變播放的速率
You change the rate of playback by setting the player’s rate property.
通過發(fā)送播放器的 rate 屬性來改變播放速率。
aPlayer.rate = 0.5;
aPlayer.rate = 2.0;
A value of 1.0 means “play at the natural rate of the current item”. Setting the rate to 0.0 is the same as pausing playback—you can also use pause.
值如果是 1.0 意味著“當前項目按正常速率播放”。將速率設置為 0.0 就和暫停播放一樣了 – 也可以使用 pause
Items that support reverse playback can use the rate property with a negative number to set the reverse playback rate. You determine the type of reverse play that is supported by using the playerItem properties canPlayReverse (supports a rate value of -1.0), canPlaySlowReverse (supports rates between 0.0 and 1.0) and canPlayFastReverse (supports rate values less than -1.0).
支持逆向播放的項目可以使用帶有負數 rate 屬性,負數可以設置反向播放速率。確定反向播放的類型,通過使用 playerItem 屬性 canPlayReverse (支持一個速率值 -1.0),canPlaySlowReverse (速率支持0.0 到 1.0)和 canPlayFastReverse (速率值可以小于 -1.0)。
Seeking—Repositioning the Playhead - 尋找-重新定位播放頭
To move the playhead to a particular time, you generally use seekToTime: as follows:
通常使用 seekToTime: 把播放頭移動到一個指定的時間,示例:
CMTime fiveSecondsIn = CMTimeMake(5, 1);
[player seekToTime:fiveSecondsIn];
The seekToTime: method, however, is tuned for performance rather than precision. If you need to move the playhead precisely, instead you use seekToTime:toleranceBefore:toleranceAfter: as in the following code fragment:
然而 seekToTime: 方法是為了性能的調試,而不是精度。如果你需要精確的移動播放頭,你需要使用 seekToTime:toleranceBefore:toleranceAfter: 代替,示例代碼:
CMTime fiveSecondsIn = CMTimeMake(5, 1);
[player seekToTime:fiveSecondsIn toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
Using a tolerance of zero may require the framework to decode a large amount of data. You should use zero only if you are, for example, writing a sophisticated media editing application that requires precise control.
After playback, the player’s head is set to the end of the item and further invocations of play have no effect. To position the playhead back at the beginning of the item, you can register to receive an AVPlayerItemDidPlayToEndTimeNotification notification from the item. In the notification’s callback method, you invoke seekToTime: with the argument kCMTimeZero.
使用一個零的限制可能需要框架來解碼大量的數據。例如應該只是用零編寫一個復雜的需要精確控制的媒體編輯應用。
播放之后,播放器的頭被設置在項目的結尾處,接著進行播放的調用沒有任何影響。將播放頭放置在項目的開始位置,可以注冊從項目接收一個 AVPlayerItemDidPlayToEndTimeNotification 消息。在消息的回調方法中,調用帶著參數 kCMTimeZero 的 seekToTime: 方法。
// Register with the notification center after creating the player item.
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:<#The player item#>];
- (void)playerItemDidReachEnd:(NSNotification *)notification {
[player seekToTime:kCMTimeZero];
}
Playing Multiple Items - 播放多個項目
You can use an AVQueuePlayer object to play a number of items in sequence. The AVQueuePlayer class is a subclass of AVPlayer. You initialize a queue player with an array of player items.
可以使用 AVQueuePlayer 對象去播放隊列中的一些項目。AVQueuePlayer 類是 AVPlayer 的子類。初始化一個帶著播放項目數組的隊列播放器:
NSArray *items = <#An array of player items#>;
AVQueuePlayer *queuePlayer = [[AVQueuePlayer alloc] initWithItems:items];
You can then play the queue using play, just as you would an AVPlayer object. The queue player plays each item in turn. If you want to skip to the next item, you send the queue player an advanceToNextItem message.
可以使用 play 播放隊列,就像你是一個 AVPlayer 對象。隊列播放器依次播放每個項目。如果想要跳過這一項,給隊列播放器發(fā)送一個 advanceToNextItem 信息。
You can modify the queue using insertItem:afterItem:, removeItem:, and removeAllItems. When adding a new item, you should typically check whether it can be inserted into the queue, using canInsertItem:afterItem:. You pass nil as the second argument to test whether the new item can be appended to the queue.
可以使用 insertItem:afterItem: ,removeItem: 和 removeAllItems 這三個方法修改隊列。當添加一個新項目,通常應該檢查它是否可以被插入到隊列中,使用 canInsertItem:afterItem:。傳 nil 作為第二個參數去測試是否將新項目添加到隊列中。
AVPlayerItem *anItem = <#Get a player item#>;
if ([queuePlayer canInsertItem:anItem afterItem:nil]) {
[queuePlayer insertItem:anItem afterItem:nil];
}
Monitoring Playback - 監(jiān)視播放
You can monitor a number of aspects of both the presentation state of a player and the player item being played. This is particularly useful for state changes that are not under your direct control. For example:
- If the user uses multitasking to switch to a different application, a player’s rate property will drop to 0.0.
- If you are playing remote media, a player item’s loadedTimeRanges and seekableTimeRanges properties will change as more data becomes available.
These properties tell you what portions of the player item’s timeline are available.
- A player’s currentItem property changes as a player item is created for an HTTP live stream.
- A player item’s tracks property may change while playing an HTTP live stream.
This may happen if the stream offers different encodings for the content; the tracks change if the player switches to a different encoding.
- A player or player item’s status property may change if playback fails for some reason.
You can use key-value observing to monitor changes to values of these properties.
可以監(jiān)視播放器的演示狀態(tài)和正在播放的播放項目的很多方面的情況。狀態(tài)的改變并不是在你的直接控制下,監(jiān)視是非常有用的。例如:
- 如果用戶使用多任務處理切換到另一個應用程序,播放器的 rate 屬性將下降到
0.0。 - 如果正在播放遠程媒體,播放項目的 loadedTimeRanges 和 seekableTimeRanges 屬性將會改變使得更多的數據成為可用的。
這些屬性告訴你,播放項目時間軸的那一部分是可用的。
- 播放器的 currentItem 屬性變化,隨著播放項目被
HTTP直播流創(chuàng)建。 - 當播放
HTTP直播流時,播放項目的 tracks 屬性可能會改變。
如果流的內容提供了不同的編碼上述情況就可能發(fā)生;如果用戶切換到不同的編碼軌道就改變了。
- 如果因為一些原因播放失敗,播放器或者播放項目的 status 屬性可能會改變。
可以使用 key-value observing 去監(jiān)視這些屬性值的改變。
Important: You should register for KVO change notifications and unregister from KVO change notifications on the main thread. This avoids the possibility of receiving a partial notification if a change is being made on another thread. AV Foundation invokes observeValueForKeyPath:ofObject:change:context: on the main thread, even if the change operation is made on another thread.
重要的是:你應該對
KVO改變通知登記,從主線程中KVO改變通知而注銷。如果在另一個線程上正在更改,這避免了只接受到部分通知的可能性。AV Foundation在主線程中調用 observeValueForKeyPath:ofObject:change:context: ,即使改變操作是在另一個線程中。
Responding to a Change in Status - 響應狀態(tài)的變化
When a player or player item’s status changes, it emits a key-value observing change notification. If an object is unable to play for some reason (for example, if the media services are reset), the status changes to AVPlayerStatusFailed or AVPlayerItemStatusFailed as appropriate. In this situation, the value of the object’s error property is changed to an error object that describes why the object is no longer be able to play.
當一個播放器或者播放項目的 status 改變,它會發(fā)出一個 key-value observing 改變通知。如果一個對象由于一些原因不能播放(例如,如果媒體服務器復位),status 適當的改變?yōu)?AVPlayerStatusFailed 或者 AVPlayerItemStatusFailed。在這種情況下,對象的 error 屬性的值被更改為一個錯誤對象,該對象描述了為什么對象不能播放了。
AV Foundation does not specify what thread that the notification is sent on. If you want to update the user interface, you must make sure that any relevant code is invoked on the main thread. This example uses dispatch_async to execute code on the main thread.
AV Foundation 沒有指定通知發(fā)送的是什么線程。如果要更新用戶界面,必須確保相關的代碼都是在主線程被調用的。這個例子使用了 dispatch_async 去執(zhí)行在主線程中的代碼。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(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:object
change:change context:context];
return;
}
Tracking Readiness for Visual Display - 為視覺展示做追蹤準備
You can observe an AVPlayerLayer object’s readyForDisplay property to be notified when the layer has user-visible content. In particular, you might insert the player layer into the layer tree only when there is something for the user to look at and then perform a transition from.
可以觀察一個 AVPlayerLayer 對象的 readyForDisplay 屬性,當層有了用戶可見的內容時屬性可以被通知。特別是,可能將播放器層插入到層樹,只有當有東西給用戶看的時候,在從里面執(zhí)行一個轉變。
Tracking Time - 追蹤時間
To track changes in the position of the playhead in an AVPlayer object, you can use addPeriodicTimeObserverForInterval:queue:usingBlock: or addBoundaryTimeObserverForTimes:queue:usingBlock:. You might do this to, for example, update your user interface with information about time elapsed or time remaining, or perform some other user interface synchronization.
- With addPeriodicTimeObserverForInterval:queue:usingBlock:, the block you provide is invoked at the interval you specify, if time jumps, and when playback starts or stops.
- With addBoundaryTimeObserverForTimes:queue:usingBlock:, you pass an array of CMTime structures contained in NSValue objects. The block you provide is invoked whenever any of those times is traversed.
追蹤一個 AVPlayer 對象中播放頭位置的變化,可以使用 addPeriodicTimeObserverForInterval:queue:usingBlock: 或者 addBoundaryTimeObserverForTimes:queue:usingBlock: ??梢赃@樣做,例如更新用戶界面與時間消耗或者剩余時間的有關信息,或者執(zhí)行一些其他用戶界面的同步。
- 有關 addBoundaryTimeObserverForTimes:queue:usingBlock: ,你提供的塊在你指定的時間間隔內被調用,如果時間有跳躍,那就在播放開始或者結束的時候。
- 有關 addBoundaryTimeObserverForTimes:queue:usingBlock:,傳遞一個
CMTime結構體的數組,包含在NSValue對象中。任何這些時間被遍歷的時候你提供的塊都會被調用。
Both of the methods return an opaque object that serves as an observer. You must keep a strong reference to the returned object as long as you want the time observation block to be invoked by the player. You must also balance each invocation of these methods with a corresponding call to removeTimeObserver:.
With both of these methods, AV Foundation does not guarantee to invoke your block for every interval or boundary passed. AV Foundation does not invoke a block if execution of a previously invoked block has not completed. You must make sure, therefore, that the work you perform in the block does not overly tax the system.
這兩種方法都返回一個作為觀察者的不透明對象。只要你希望播放器調用時間觀察的塊,就必須對返回的對象保持一個強引用。你也必須平衡每次調用這些方法,與相應的調用 removeTimeObserver:.
有了這兩種方法, AV Foundation 不保證每個間隔或者通過邊界時都調用你的塊。如果以前調用的塊執(zhí)行沒有完成,AV Foundation不會調用塊。因此必須確保你在該塊中執(zhí)行的工作不會對系統(tǒng)過載。
// 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);
}];
Reaching the End of an Item - 到達一個項目的結束
You can register to receive an AVPlayerItemDidPlayToEndTimeNotification notification when a player item has completed playback.
當一個播放項目已經完成播放的時候,可以注冊接收一個 AVPlayerItemDidPlayToEndTimeNotification 通知。
[[NSNotificationCenter defaultCenter] addObserver:<#The observer, typically self#>
selector:@selector(<#The selector name#>)
name:AVPlayerItemDidPlayToEndTimeNotification
object:<#A player item#>];
Putting It All Together: Playing a Video File Using AVPlayerLayer - 總而言之,使用 AVPlayerLayer 播放視頻文件
This brief code example illustrates how you can use an AVPlayer object to play a video file. It shows how to:
- Configure a view to use an AVPlayerLayer layer
- Create an AVPlayer object
- Create an AVPlayerItem object for a file-based asset and use key-value observing to observe its status
- Respond to the item becoming ready to play by enabling a button
- Play the item and then restore the player’s head to the beginning
這個簡短的代碼示例演示如何使用一個 AVPlayer 對象播放一個視頻文件。它顯示了如何:
- 使用
AVPlayerLayer層配置視圖 - 創(chuàng)建一個
AVPlayer對象 - 創(chuàng)建一個基于文件資產的
AVPlayerItem對象和使用key-value observing去觀察它的狀態(tài) - 通過啟用按鈕來響應項目準備就緒播放
- 播放項目,然后將播放器的頭重置到開始位置
Note: To focus on the most relevant code, this example omits several aspects of a complete application, such as memory management and unregistering as an observer (for key-value observing or for the notification center). To use AV Foundation, you are expected to have enough experience with Cocoa to be able to infer the missing pieces.
注意:關注最相關的代碼,這個例子中省略了一個完整應用程序的幾個方面,比如內存管理和注銷觀察者(
key-value observing或者notification center)。為了使用AV Foundation,你應該有足夠的Cocoa經驗,有能力去推斷出丟失的碎片。
For a conceptual introduction to playback, skip to Playing Assets.
對于播放的概念性的介紹,跳去看 Playing Assets。
The Player View - 播放器視圖
To play the visual component of an asset, you need a view containing an AVPlayerLayer layer to which the output of an AVPlayer object can be directed. You can create a simple subclass of UIView to accommodate this:
播放一個資產的可視化部分,需要一個包含了 AVPlayerLayer 層的視圖,AVPlayerLayer 層可以直接輸出 AVPlayer 對象。可以創(chuàng)建一個 UIView 的簡單子類來容納:
#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
A Simple View Controller - 一個簡單的 View Controller
Assume you have a simple view controller, declared as follows:
假設你有一個簡單的 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;
@ends
The syncUI method synchronizes the button’s state with the player’s state:
syncUI 方法同步按鈕狀態(tài)和播放器的狀態(tài):
- (void)syncUI {
if ((self.player.currentItem != nil) &&
([self.player.currentItem status] == AVPlayerItemStatusReadyToPlay)) {
self.playButton.enabled = YES;
}
else {
self.playButton.enabled = NO;
}
}
You can invoke syncUI in the view controller’s viewDidLoad method to ensure a consistent user interface when the view is first displayed.
當視圖第一次顯示的時候,可以在視圖控制器的 viewDidLoad 方法中調用 invoke 去確保用戶界面的一致性。
- (void)viewDidLoad {
[super viewDidLoad];
[self syncUI];
}
The other properties and methods are described in the remaining sections.
在其余章節(jié)描述其他屬性和方法。
Creating the Asset - 創(chuàng)建一個資產
You create an asset from a URL using AVURLAsset. (The following example assumes your project contains a suitable video resource.)
使用 AVURLAsset 從一個 URL 創(chuàng)建一個資產。(下面的例子假設你的工程包含了一個合適的視頻資源)
- (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.
}];
}
In the completion block, you create an instance of AVPlayerItem for the asset and set it as the player for the player view. As with creating the asset, simply creating the player item does not mean it’s ready to use. To determine when it’s ready to play, you can observe the item’s status property. You should configure this observing before associating the player item instance with the player itself.
You trigger the player item’s preparation to play when you associate it with the player.
在完成塊中,為資產創(chuàng)建一個 AVPlayerItem 的實例,并設置它為播放頁面的播放器。與創(chuàng)建資產一樣,簡單地創(chuàng)建播放器項目并不意味著它已經準備好使用。為了確定它已經準備好了,可以觀察項目的 status 屬性。你應該在該播放器項目實例與播放器本身關聯之前,配置這個 observing 。
當你將它與播放器連接時,就是觸發(fā)播放項目的播放準備。
// 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:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object: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]);
}
});s
Responding to the Player Item’s Status Change - 相應播放項目的狀態(tài)改變
When the player item’s status changes, the view controller receives a key-value observing change notification. AV Foundation does not specify what thread that the notification is sent on. If you want to update the user interface, you must make sure that any relevant code is invoked on the main thread. This example uses dispatch_async to queue a message on the main thread to synchronize the user interface.
當播放項目的狀態(tài)改變時,視圖控制器接收一個 key-value observing 改變通知。AV Foundation 沒有指定通知發(fā)送的是什么線程。如果你想更新用戶界面,必須確保任何相關的代碼都要在主線程中調用。這個例子使用 dispatch_async 讓主線程同步用戶界面的消息進入隊列。
Playing the Item - 播放項目
Playing the item involves sending a play message to the player.
播放項目涉及到想播放器發(fā)送一個播放消息。
- (IBAction)play:sender {
[player play];
}
The item is played only once. After playback, the player’s head is set to the end of the item, and further invocations of the play method will have no effect. To position the playhead back at the beginning of the item, you can register to receive an AVPlayerItemDidPlayToEndTimeNotification from the item. In the notification’s callback method, invoke seekToTime: with the argument kCMTimeZero.
該項目只播放一次。播放之后,播放器的頭被設置在項目的結束位置,播放方法進一步調用將沒有效果。將播放頭放在項目的開始,可以注冊從項目去接收 AVPlayerItemDidPlayToEndTimeNotification。在通知的回調方法,調用帶著參數 kCMTimeZero 的 seekToTime: 方法。
// Register with the notification center after creating the player item.
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[self.player currentItem]];
- (void)playerItemDidReachEnd:(NSNotification *)notification {
[self.player seekToTime:kCMTimeZero];
}

