サーバーからオーディオをストリーミングするためにAVPlayer
を正常に使用しています。ここでしたいことは、バッファリングの進行状況を表示するカスタムUISlider
を表示することです。
このようなもの:
AVPlayer
では、オーディオファイルの合計ダウンロードサイズや現在のダウンロード量を取得する方法はなく、現在の再生時間と合計再生時間しか取得できません。
これには回避策がありますか?
私はこれに取り組んでいます、そして今のところ以下があります:
- (NSTimeInterval) availableDuration;
{
NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
NSTimeInterval result = startSeconds + durationSeconds;
return result;
}
それはうまくいくはずです:
Objective-C:
- (CMTime)availableDuration
{
NSValue *range = self.player.currentItem.loadedTimeRanges.firstObject;
if (range != nil){
return CMTimeRangeGetEnd(range.CMTimeRangeValue);
}
return kCMTimeZero;
}
Swiftバージョン:
func availableDuration() -> CMTime
{
if let range = self.player?.currentItem?.loadedTimeRanges.first {
return CMTimeRangeGetEnd(range.timeRangeValue)
}
return .zero
}
現在の時間値を監視するには、次のように使用できます。CMTimeShow([self availableDuration]);orCMTimeShow(availableDuration ())(Swiftの場合)
個人的には、timeRangesの値が常に1になることに同意しません。
ドキュメントによると
配列には、プレーヤー項目のメディアデータがすぐに利用できる時間範囲を示すCMTimeRange値を含むNSValueオブジェクトが含まれています。返される時間範囲は不連続である可能性があります。
したがって、これは次のような値になる場合があります。
[(開始1、終了1)、(開始2、終了2)]
デスクトップWebの世界でのhls.jsフレームワークの私の経験から、これらの時間範囲の間の穴は、シーク、不連続性などのさまざまな要因に応じて非常に小さい場合と大きい場合があります。
したがって、バッファの合計長を正しく取得するには、配列をループして、各項目と連結の期間を取得する必要があります。
現在の再生ヘッドからバッファ値を探している場合は、現在の時間よりも大きい開始時間と現在の時間よりも短い終了時間の時間範囲をフィルタリングする必要があります。
public extension AVPlayerItem {
public func totalBuffer() -> Double {
return self.loadedTimeRanges
.map({ $0.timeRangeValue })
.reduce(0, { acc, cur in
return acc + CMTimeGetSeconds(cur.start) + CMTimeGetSeconds(cur.duration)
})
}
public func currentBuffer() -> Double {
let currentTime = self.currentTime()
guard let timeRange = self.loadedTimeRanges.map({ $0.timeRangeValue })
.first(where: { $0.containsTime(currentTime) }) else { return -1 }
return CMTimeGetSeconds(timeRange.end) - currentTime.seconds
}
}
Objective CのSuresh Kansujiyaのコード
NSTimeInterval bufferAvail;
if (player.currentItem != nil) {
AVPlayerItem *item = player.currentItem;
if (item.status == AVPlayerStatusReadyToPlay) {
NSArray *timeRangeArray = item.loadedTimeRanges;
CMTimeRange aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];
Float64 startTime = CMTimeGetSeconds(aTimeRange.start);
Float64 loadedDuration = CMTimeGetSeconds(aTimeRange.duration);
bufferAvail = startTime + loadedDuration;
NSLog(@"%@ - %f", [self class], bufferAvail);
} else {
NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid)); }
}
else {
NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid));
}
このメソッドは、UISliderのバッファー時間間隔を返します
public var bufferAvail: NSTimeInterval {
// Check if there is a player instance
if ((player.currentItem) != nil) {
// Get current AVPlayerItem
var item: AVPlayerItem = player.currentItem
if (item.status == AVPlayerItemStatus.ReadyToPlay) {
var timeRangeArray: NSArray = item.loadedTimeRanges
var aTimeRange: CMTimeRange = timeRangeArray.objectAtIndex(0).CMTimeRangeValue
var startTime = CMTimeGetSeconds(aTimeRange.start)
var loadedDuration = CMTimeGetSeconds(aTimeRange.duration)
return (NSTimeInterval)(startTime + loadedDuration);
}
else {
return(CMTimeGetSeconds(kCMTimeInvalid))
}
}
else {
return(CMTimeGetSeconds(kCMTimeInvalid))
}
}
返された配列が空の場合、選択した回答によって問題が発生する可能性があります。これは固定関数です:
- (NSTimeInterval) availableDuration
{
NSArray *loadedTimeRanges = [[_player currentItem] loadedTimeRanges];
if ([loadedTimeRanges count])
{
CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
NSTimeInterval result = startSeconds + durationSeconds;
return result;
}
return 0;
}