AVPlayerLoop не бесшовно зацикливается - Swift 4 - PullRequest
0 голосов
/ 21 декабря 2018

Моя проблема: я пытаюсь сделать бесшовное зацикливание (я намерен сделать мой AVPlayer или AVPlayerQueue зацикливаться без задержки между воспроизведением).Так, например, если я делаю видео и иду к воспроизведению, оно должно бесконечно зацикливаться без каких-либо скачков или задержек в цикле.

Я написал код ниже (он прямо из примера кода):

    var playerQQ: AVQueuePlayer!
    var playerLayur: AVPlayerLayer!
    var playerEyetem: AVPlayerItem!
    var playerLooper: AVPlayerLooper!

    func playRecordedVideo(videoURL: URL) {

        playerQQ = AVQueuePlayer()
        playerLayur = AVPlayerLayer(player: playerQQ)
        playerLayur.frame = (camBaseLayer?.bounds)! 
       camBaseLayer?.layer.insertSublayer(playerLayur, above: previewLayer) 

       playerEyetem = AVPlayerItem(url: videoURL)
        playerLooper = AVPlayerLooper(player: playerQQ, templateItem: playerEyetem)
        playerQQ.play()

    }

Код выше не зацикливается;между концом текущего плеера и следующего появляется всплески.Я много пытался найти проблему и искал ее в Интернете, но не нашел решения.Кроме того, я пробовал NSNotifications и другие методы, включая установку Player.seek (в: ноль), когда проигрыватель заканчивает воспроизведение.Но ничего не сработало.

Любая помощь будет оценена :) 1008 *

Ответы [ 3 ]

0 голосов
/ 24 декабря 2018

При зацикливании ресурсов следует иметь в виду, что аудио- и видеодорожки могут иметь разное смещение и разную длительность, что приводит к «бликам» при зацикливании.Такие небольшие различия довольно распространены в учтенных активах.

Перебор треков и печать временных диапазонов может помочь обнаружить такие ситуации: for track in asset.tracks { print( track.mediaType); CMTimeRangeShow( track.timeRange); }

Чтобы обрезать аудио- и видеодорожки до одинакового времени начала и одинаковой продолжительности, получите общий диапазон временидорожек, а затем вставьте этот временной диапазон из исходного ресурса в новый AVMutableComposition.Как правило, вы также хотите сохранить свойства, такие как ориентация видеодорожки:

let asset: AVAsset = (your asset initialization here)

let videoTrack: AVAssetTrack = asset.tracks(withMediaType: .video).first!
let audioTrack: AVAssetTrack = asset.tracks(withMediaType: .audio).first!

// calculate common time range of audio and video track
let timeRange: CMTimeRange = CMTimeRangeGetIntersection( (videoTrack.timeRange), (audioTrack.timeRange))

let composition: AVMutableComposition = AVMutableComposition()

try composition.insertTimeRange(timeRange, of: asset, at: kCMTimeZero)

// preserve orientation
composition.tracks(withMediaType: .video).first!.preferredTransform = videoTrack.preferredTransform

Поскольку AVMutableComposition является подклассом AVAsset, его можно использовать для циклического воспроизведения на основе AVPlayerLooper или экспорта с помощью AVAssetExportSession.

Я поместил более полную реализацию усечения на github: https://github.com/fluthaus/NHBAVAssetTrimming. Он более устойчив, обрабатывает несколько дорожек, сохраняет больше свойств и может быть легко интегрирован в проекты или может быть собран какавтономная утилита обрезки фильмов в командной строке macOS.

0 голосов
/ 24 декабря 2018

Ответ от @NoHalfBits прекрасно работает, но я также нашел другое решение.Я в основном получил диапазон времени пересечения видео и звука mediaTypes из ресурса playerItem.После этого я добавил intersectionTimeRange в качестве timeRange в параметр, когда я вызываю:

playerLooper = AVPlayerLooper(playerQueue:_, playerItem:_, timeRange: intersectionTimeRange)

Это будет работать!Чтобы получить timeRanges каждого из них, установите цикл for для актива playerItem.

0 голосов
/ 21 декабря 2018

Если вы играете в конце, попробуйте

NotificationCenter.default.addObserver(self,
                                       selector: #selector(playerItemDidReachEnd(notification:)),
                                       name: Notification.Name.AVPlayerItemDidPlayToEndTime,
                                       object: avPlayer?.currentItem)

 @objc func playerItemDidReachEnd(notification: Notification) {
        if let playerItem: AVPlayerItem = notification.object as? AVPlayerItem {
            playerItem.seek(to: kCMTimeZero, completionHandler: nil)
        }
    }

Если нет, я бы посоветовал управлять своим с помощью dTime (запустить NSTimer 1/30 секунд или что-то в этом роде) и настроить для игры с чем-то вроде этого

    player.seekToTime(seekTimeInProgress, toleranceBefore: kCMTimeZero,
            toleranceAfter: kCMTimeZero, completionHandler: ...

kCMTimeZero чрезвычайно важны, иначе время не будет точным.И, наконец, я обнаружил, что при перезапуске видео есть время загрузки, в зависимости от типа телефона на iOS и продолжительности видео, а также от того, сколько вы играете, поэтому, если вы по-прежнему испытываете это отставание после устранения проблем с синхронизацией,может быть принужден к учету в вашем UX.

...