AVPlayerde 無縫快進和倒放.

weixin_33866037發表於2018-04-27

最近研究一個AVPlayer seekTime方法的 問題.這個方法雖然可以跳到指定的幀,但是如果你用拖動框去調動這個方法,你會發現這個方法會延遲.
我們檢視系統的播放器,你會發現他是不會延遲.拖到哪就能顯示當前幀.
我們查詢API發現seekTime 還有一個

- (void)seekToTime:(CMTime)time toleranceBefore:(CMTime)toleranceBefore toleranceAfter:(CMTime)toleranceAfter completionHandler:(void (^)(BOOL finished))completionHandler

這個方法發現官方的解釋是:

在指定的時間範圍內移動回放游標,並在查詢操作完成或中斷時呼叫指定的塊。
使用此方法可以查詢當前播放器專案的指定時間,並在查詢操作完成時收到通知。
要求的時間將在[時間容差前,時間+容差後]範圍內,並且可能與指定的效率時間不同。
將kCMTimeZero傳遞給toleranceBefore和toleranceAfter以請求取樣精確搜尋,這可能會導致額外的解碼延遲。
使用beforeTolerance訊息傳遞此方法:kCMTimePositiveInfinity和afterTolerance:kCMTimePositiveInfinity與訊息傳遞seekToTime:直接相同。
任何之前正在處理的查詢請求的完成處理程式將立即呼叫,並將完成的引數設定為NO。如果新的
請求完成而不被另一個查詢請求或任何其他操作中斷,指定的完成處理程式將被呼叫
完成引數設定為YES。

沒錯這個就是我們要找個.但是當你換成這個方法的時候,你會發現,沒什麼**用.
我們深究官方的解釋我們要理解

任何之前正在處理的查詢請求的完成處理程式將立即呼叫,並將完成的引數設定為NO。如果新的
請求完成而不被另一個查詢請求或任何其他操作中斷,指定的完成處理程式將被呼叫
完成引數設定為YES。

這幾句話.是說completionHandler 沒有完成的情況下不呼叫這個方法.如果你不間斷呼叫seekTime的 話,則會造成前個seekTime操作的中斷.我們只需要加個BOOL值就可以了.
上程式碼

- (void)processMovie:(NSURL*)assetURL{

    AVAsset *asset = [AVAsset assetWithURL:assetURL];
    float totalTime = CMTimeGetSeconds(asset.duration);
    process =  self.selectView.frame.origin.x / self.selectImageView.frame.size.width;
    NSLog(@"%f",process);
    [self.player pause];
    CMTime newChaseTime = CMTimeMake(totalTime * process * asset.duration.timescale, asset.duration.timescale);
    if (CMTIME_COMPARE_INLINE(newChaseTime, !=, chaseTime)) {
        chaseTime = newChaseTime;
        if (!isSeekInProgress) {
            [self trySeekToChaseTime];
        }
    }
    [self onVideoPlayerProgressUpdate];
}
- (void)trySeekToChaseTime{
    if (_player.currentItem.status == AVPlayerItemStatusUnknown) {
        
    } else if (_player.currentItem.status == AVPlayerItemStatusReadyToPlay){
        [self actuallySeekToTime];
    }
}

- (void)actuallySeekToTime{
    isSeekInProgress = YES;
    CMTime seekTimeInProgress = chaseTime;
    [self.player seekToTime:seekTimeInProgress
            toleranceBefore:kCMTimeZero
             toleranceAfter:kCMTimeZero
          completionHandler:^(BOOL finished) {
              if (CMTIME_COMPARE_INLINE(seekTimeInProgress, ==, chaseTime)) {
                  isSeekInProgress = NO;
              } else {
                  [self trySeekToChaseTime];
              }
          }];
}

效果:


4676869-0e9db5c54ee6fff5.gif

原創文章轉載需獲授權並註明出處
請在後臺留言聯絡轉載

相關文章