簡體   English   中英

Avplayer AVPlayerItemDidPlayToEndTime 通知未向觀察者發送消息

[英]Avplayer AVPlayerItemDidPlayToEndTime notificaton not sending message to observer

我正在使用AVQueuePlayer播放遠程音頻文件列表。 我想默認實現重復所有。

我的方法是,我正在觀察AVPlayerItemDidPlayToEndTime通知,並在播放完畢后將 playerItem 添加到隊列的后面。

nextAudio(notification: Notification)根本沒有運行。 需要這方面的幫助,或者更好的方式來實現無限游戲。

func playAudio(_ items: [AVPlayerItem]) {

    let avPlayerVC = AVPlayerViewController()
    let player = AVQueuePlayer(items: items)
    player.actionAtItemEnd = .pause
    avPlayerVC.player = player

    for item in items {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(FilesViewController.nextAudio(notification:)),
                                               name: .AVPlayerItemDidPlayToEndTime, object: item)
    }

    present(avPlayerVC, animated: true) {
        self.player.play()
    }
}

@objc func nextAudio(notification: Notification) {
    debugPrint("nextAudio was called")
    guard player != nil else { return }
    debugPrint("AVPlayerItemDidPlayToEndTime notif info  \(notification.userInfo)")
    if let currentItem = notification.userInfo!["object"] as? AVPlayerItem {
        currentItem.seek(to: kCMTimeZero)
        self.player.advanceToNextItem()
        self.player.insert(currentItem, after: nil)
    }
}

我相信你已經明白了,但我只是遇到了自己,並決定回答:

當您指定通知對象時,它看起來似乎沒有傳遞(順便說一句,這應該是一種正確的方式)。 可能是iOS中的一個錯誤...

你需要通過nil代替:

NotificationCenter.default.addObserver(self, selector: #selector(videoDidPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)

然后在方法中,您應該檢查通知的對象是您的播放器項目。 文檔實際上並不一致,因為 Apple 聲明通知的對象是AVplayer但它是AVPlayerItem

@objc
    private func videoDidPlayToEnd(_ notification: Notification) {
        guard let playerItem = notification.object as? AVPlayerItem, let urlAsset = playerItem.asset as? AVURLAsset else { return }
    gpLog("Sender urlAsset: \(urlAsset.url.absoluteString)")
        // Compare an asset URL.
    }

謝謝@Lukasz 的精彩回答! 我遇到了多個視頻在錯誤時間觸發通知的問題。 你的回答幫助我解決了它。

如果有人正在尋找如何在SwiftUI 中使用它的示例,這里是我的代碼:

首先創建一個播放器:

import SwiftUI
import AVKit

struct VideoPlayer : UIViewControllerRepresentable {

func makeCoordinator() -> VideoPlayer.Coordinator {
    return VideoPlayer.Coordinator(parent1: self)
}

@Binding var didFinishVideo : Bool
@Binding var player : AVPlayer
var play: Bool
var loop: Bool
var videoName: String
var controller = AVPlayerViewController()

func makeUIViewController(context: UIViewControllerRepresentableContext<VideoPlayer>) -> AVPlayerViewController {
    controller.player = player
    controller.showsPlaybackControls = false
    controller.videoGravity = .resize
    NotificationCenter.default.addObserver(context.coordinator, selector: #selector(context.coordinator.playerDidFinishPlaying(_:)), name: .AVPlayerItemDidPlayToEndTime, object: nil)
    return controller
}

func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<VideoPlayer>) {
    if play {
        player.play()
    }
}

class Coordinator : NSObject{
    var parent : VideoPlayer
    init(parent1 : VideoPlayer) {
        parent = parent1
    }

    @objc func playerDidFinishPlaying(_ notification: Notification) {
        guard let playerItem = notification.object as? AVPlayerItem, let urlAsset = playerItem.asset as? AVURLAsset else { return }
        print("Sender urlAsset: \(urlAsset.url.absoluteString)")

        if urlAsset.url.absoluteString.contains(parent.videoName) {
            if parent.loop {
                parent.player.seek(to: CMTime.zero)
                parent.player.play()
            } else {
                parent.didFinishVideo = true
            }
        }

    }

}
}

您可以使用它來創建多個視頻,如下所示:

import SwiftUI
import AVKit

struct ExampleVideo: View {
    @Binding var didFinishVideo : Bool
    var play: Bool
    @State private var player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "exampleVideoFileName", ofType: "mp4")!))
    var body: some View {
        VideoPlayer(didFinishVideo: $didFinishVideo, player: $player, play: play, loop: false, videoName: "exampleVideoFileName")
    }
}

struct ExampleVideo_Previews: PreviewProvider {
    static var previews: some View {
        CeveraIntroVideo(didFinishVideo: .constant(true), play: true)
    }
}

這是在加載某些內容后在視圖中使用它的示例:

struct IntroScreens: View {

@State var loadingComplete = false
@State var didFinishVideo = false

var body: some View {
        ZStack{
            ExampleVideo(didFinishVideo: $didFinishVideo, play: loadingComplete)
                .zIndex(loadingComplete ? 3 : 0)
                .animation(Animation.easeInOut(duration: 1))
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM