iOS 10 でAvPlayerLooperが追加
iOS 10からAVPlayerLooperが追加されて、ループ再生をかんたんに実現することができるようになりました。
試してみる前に、まずはWWDC 2016のビデオを観るのがおすすめです。ループ関連の説明は13:00からはじまります。
iOS 9でも、AVQueuePlayerを工夫して使えばシームレスなループ再生ができましたが、いろいろと面倒でした。iOS 10からはAVPlayerLooperを使えば、シンプルな実装でシームレスなループ再生を実現できます。
試しに、Appleが提供しているサンプルプログラムを動かしてみるのが分かりやすいです。AVPlayerLooperと、AVQueuePlayerを使った場合のそれぞれの実装を比較することができます。
AVPlayerLooperを使うと、startTime秒からendTime秒までループしたい場合は、以下のようなコードを書くだけでOK。
let asset = // AVAsset with its 'duration' property value loaded
let playerItem = AVPlayerItem(asset: asset)
// Create a new player looper with the queue player and template item
playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: playerItem)
let timescale = playerItem.duration.timescale
let start = CMTime(seconds: startTime, preferredTimescale: timescale)
let end = CMTime(seconds: endTime, preferredTimescale: timescale)
let timeRange = CMTimeRange(start: start, end: end)
// Create a new player looper with the queue player, template item, and time range
playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: playerItem, timeRange: timeRange)
// Begin looping playback
queuePlayer.play()
ちょっと困ること
1つ気をつけないといけないのが、ループ範囲を設定すると、再生位置が自動的にループの開始位置にシークされてしまうこと。
Time range looping will be accomplished by seeking to the time range’s start time and setting player item’s forwardPlaybackEndTime property on the looping item replicas.
この仕様、場合によっては困ります。例えば、曲のA-B区間をループ再生中に、ループ区間を解除してそのまま通常再生を続けたい場合、この仕様だと、ループを解除すると、曲の先頭に勝手にシークされてしまいます。
回避策として、ループ解除前に、現在の再生位置を保存しておいて、ループ区間を解除した後に、保存しておいた再生位置にシークし直せばいいのですが、どうしても不連続になるので、ビデオとオーディオが途切れてしまいます。
この点について、Apple Bug Reporter経由で問い合わせてみたのですが、AVQueuePlayerをベースにしているため現状の仕様とのこと。改善を検討します、とは言っていましたが、まぁきっとすぐには実現されないでしょう。
実装例
私が開発しているPlaySectionsのバージョン2.0.0でビデオ再生機能を追加したのですが、その際にAVPlayerLooperを使ってループ機能を実装しました。興味ある方はお試しください。