天天看點

AVFoundation Programming Guide(官方文檔翻譯3)Playback - 播放Playback - 播放

新部落格:

完整版 - AVFoundation Programming Guide

分章節版:

– 第1章:About AVFoundation - AVFoundation概述

– 第2章:Using Assets - 使用Assets

– 第3章:Playback - 播放

– 第4章:Editing - 編輯

– 第5章:Still and Video Media Capture - 靜态視訊媒體捕獲

– 第6章:Export - 輸出

– 第7章:Time and Media Representations 時間和媒體表現

CSDN部落格:

完整版 - AVFoundation Programming Guide

分章節版:

– 第1章:About AVFoundation - AVFoundation概述

– 第2章:Using Assets - 使用Assets

– 第3章:Playback - 播放

– 第4章:Editing - 編輯

– 第5章:Still and Video Media Capture - 靜态視訊媒體捕獲

– 第6章:Export - 輸出

– 第7章:Time and Media Representations 時間和媒體表現

版權聲明:本文為部落客原創翻譯,如需轉載請注明出處。

蘋果源文檔位址 - 點選這裡

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 執行個體去管理資産作為一個整體的顯示狀态,AVPlayerItemTrack 對象來管理一個單獨軌道的顯示狀态。使用 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

系統中,可以選擇使用

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.

播放器提供了關于播放狀态的資訊,是以如果需要,可以将使用者界面與播放器的狀态同步。通常将播放器的輸出指向專門的動畫核心層(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

執行個體建立許多

AVPlayerLayer

對象,但是隻有最近被建立的那一層将會螢幕上顯示視訊的内容。

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

管理與它相關的資産的顯示狀态。一個

player item

包含了播放器項目軌道 – AVPlayerItemTrack—that 的執行個體,對應資産内的軌道。各個對象之間的關系如圖2-1所示。

AVFoundation Programming Guide(官方文檔翻譯3)Playback - 播放Playback - 播放

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顯示了一種可能性,同一個資産有兩個不同的播放器,并且有不同的設定。可以使用不同的項目軌道,在播放期間禁用一個特定的軌道(例如,你可能不想播放這個聲音元件)。

AVFoundation Programming Guide(官方文檔翻譯3)Playback - 播放Playback - 播放

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

将為資源建立和配置資産)。即使帶着

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 建立一個資産
  • 使用資産建立一個

    AVPlayerItem

    的執行個體
  • AVPlayer

    的執行個體與項目聯結
  • 等待,直到項目的

    status

    屬性表明已經準備好播放了(通常當狀态改變時,使用 key-value observing 接受通知)

該方法的說明都在:Putting It All Together: Playing a Video File Using AVPlayerLayer

建立和編寫能夠播放的HTTP直播流媒體。使用

URL

初始化一個

AVPlayerItem

的執行個體。(你不能直接建立一個

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: 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.

當你把播放項目和播放器聯結起來時,它開始準備播放。當它準備播放時,播放項目建立

AVAsset

AVAssetTrack

執行個體,可以用它來檢查直播流的内容。

擷取一個流項目的持續時間,可以觀察播放項目的 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,持續時間可以被下面的代碼擷取到:
[[[[[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

直接建立一個播放器,代碼如下:

self.player = [AVPlayer playerWithURL:<#Live stream URL#>];
[player addObserver:self forKeyPath:@"status" options: 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 屬性去通路被流所建立播放項目。

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

    建立一個

    AVPlayerItem

    。觀察這個播放器的 status 屬性來決定它是否是可播放的。

如果兩個都可以成功,你最終用可以聯結給一個播放器的播放項目。

Playing an Item - 播放一個項目

To start playback, you send a play message to the player.

發送一個播放消息給播放器,開始播放:

- (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.

除了簡單的播放,可以管理播放的各個方面,如速度和播放頭的位置。也可以監視播放器的播放狀态;這是很有用的,例如如果你想将使用者界面同步到資産的呈現狀态 – 詳情看:Monitoring Playback.

Changing the Playback Rate - 改變播放的速率

You change the rate of playback by setting the player’s rate property.

通過發送播放器的 rate 屬性來改變播放速率。

aPlayer.rate = ;
aPlayer.rate = ;
           

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

對象。隊列播放器依次播放每個項目。如果想要跳過這一項,給隊列播放器發送一個 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 - 監視播放

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.

可以監視播放器的示範狀态和正在播放的播放項目的很多方面的情況。狀态的改變并不是在你的直接控制下,監視是非常有用的。例如:

  • 如果使用者使用多任務處理切換到另一個應用程式,播放器的 rate 屬性将下降到

    0.0

  • 如果正在播放遠端媒體,播放項目的 loadedTimeRanges 和 seekableTimeRanges 屬性将會改變使得更多的資料成為可用的。

這些屬性告訴你,播放項目時間軸的那一部分是可用的。

  • 播放器的 currentItem 屬性變化,随着播放項目被

    HTTP

    直播流建立。
  • 當播放

    HTTP

    直播流時,播放項目的 tracks 屬性可能會改變。

如果流的内容提供了不同的編碼上述情況就可能發生;如果使用者切換到不同的編碼軌道就改變了。

  • 如果因為一些原因播放失敗,播放器或者播放項目的 status 屬性可能會改變。

可以使用

key-value observing

去監視這些屬性值的改變。

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 - 響應狀态的變化

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

改變,它會發出一個

key-value observing

改變通知。如果一個對象由于一些原因不能播放(例如,如果媒體伺服器複位),

status

适當的改變為 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

沒有指定通知發送的是什麼線程。如果要更新使用者界面,必須確定相關的代碼都是在主線程被調用的。這個例子使用了 dispatch_async 去執行在主線程中的代碼。

- (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 屬性,當層有了使用者可見的内容時屬性可以被通知。特别是,可能将播放器層插入到層樹,隻有當有東西給使用者看的時候,在從裡面執行一個轉變。

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: 。可以這樣做,例如更新使用者界面與時間消耗或者剩餘時間的有關資訊,或者執行一些其他使用者界面的同步。

  • 有關 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

不保證每個間隔或者通過邊界時都調用你的塊。如果以前調用的塊執行沒有完成,

AV Foundation

不會調用塊。是以必須確定你在該塊中執行的工作不會對系統過載。

// Assume a property: @property (strong) id playerObserver;

Float64 durationSeconds = CMTimeGetSeconds([<#An asset#> duration]);
CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/, );
CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*/, );
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

    層配置視圖
  • 建立一個

    AVPlayer

    對象
  • 建立一個基于檔案資産的

    AVPlayerItem

    對象和使用

    key-value observing

    去觀察它的狀态
  • 通過啟用按鈕來響應項目準備就緒播放
  • 播放項目,然後将播放器的頭重置到開始位置

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 對象。可以建立一個 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;
@end
           

The syncUI method synchronizes the button’s state with the player’s state:

syncUI

方法同步按鈕狀态和播放器的狀态:

- (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.

在其餘章節描述其他屬性和方法。

Creating the Asset - 建立一個資産

You create an asset from a URL using AVURLAsset. (The following example assumes your project contains a suitable video resource.)

使用 AVURLAsset 從一個

URL

建立一個資産。(下面的例子假設你的工程包含了一個合适的視訊資源)

- (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.

在完成塊中,為資産建立一個 AVPlayerItem 的執行個體,并設定它為播放頁面的播放器。與建立資産一樣,簡單地建立播放器項目并不意味着它已經準備好使用。為了确定它已經準備好了,可以觀察項目的

status

屬性。你應該在該播放器項目執行個體與播放器本身關聯之前,配置這個

observing

當你将它與播放器連接配接時,就是觸發播放項目的播放準備。

// 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]);
                }
            });
           

Responding to the Player Item’s Status Change - 相應播放項目的狀态改變

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.

當播放項目的狀态改變時,視圖控制器接收一個

key-value observing

改變通知。

AV Foundation

沒有指定通知發送的是什麼線程。如果你想更新使用者界面,必須確定任何相關的代碼都要在主線程中調用。這個例子使用 dispatch_async 讓主線程同步使用者界面的消息進入隊列。

Playing the Item - 播放項目

Playing the item involves sending a play message to the player.

播放項目涉及到想播放器發送一個播放消息。

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