Инициализация SKVideoNode с использованием объекта AVPlayer - SWIFT

Я играю с ARKit и создал приложение, которое накладывает видеоконтент на распознанные изображения. Код выглядит следующим образом:

import UIKit
import SceneKit
import ARKit
import SpriteKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()

        sceneView.delegate = self

    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let configuration = ARImageTrackingConfiguration()

        if let imageToTrack = ARReferenceImage.referenceImages(inGroupNamed: "ALLimages", bundle: Bundle.main) {

            configuration.trackingImages = imageToTrack

            configuration.maximumNumberOfTrackedImages = 3

            print("Images successfully added")

        }

        sceneView.session.run(configuration)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        sceneView.session.pause()
    }

    // MARK: - ARSCNViewDelegate

    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        let node = SCNNode()

        var videoNode = SKVideoNode()

        var videoScene = SKScene()

        if let imageAnchor = anchor as? ARImageAnchor {


            videoNode = SKVideoNode(fileNamed: "video1.mp4")

            videoNode.play()

            videoScene = SKScene(size: CGSize(width: 640, height: 360))

            videoNode.position = CGPoint(x: videoScene.size.width / 2, y: videoScene.size.height / 2)

            videoNode.yScale = -1.0

            videoScene.addChild(videoNode)

            let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height)

             plane.firstMaterial?.diffuse.contents = videoScene

            let planeNode = SCNNode(geometry: plane)

            planeNode.eulerAngles.x = -.pi/2

            node.addChildNode(planeNode)

        }
        return node
    }
}

Это прекрасно работает ... однажды! Но проблема в том, что после завершения воспроизведения видео из-за ограниченных элементов управления, доступных через SKVideoNode, я не могу понять, как автоматически перезапустить видео. В идеале они должны воспроизводиться в виде петли.

Я провел некоторое исследование, и мне кажется, что лучший способ - это инициализировать мой видеоузел с помощью объекта AVPlayer.

Итак, я попытался сделать это, но не могу заставить его работать.

Я добавил var player = AVPlayer () в свой класс, а затем попытался инициализировать свой videoNode следующим образом:

var videoNode: SKVideoNode? = {
    guard let urlString = Bundle.main.path(forResource: "video1", ofType: "mov") else {
        return nil
    }

    let url = URL(fileURLWithPath: urlString)
    let item = AVPlayerItem(url: url)
    let player = AVPlayer(playerItem: item)

    return SKVideoNode(avPlayer: player)
}()

Затем я попытался использовать player.play (), но видео не воспроизводится. Вместо этого мой самолет просто выглядит как пустой прямоугольник над моими изображениями.

Как только я успешно инициализирую это, я думаю, что смогу добавить наблюдателя, чтобы проверить, когда видео закончил проигрыватель, и перезапустить его, но я изо всех сил пытаюсь добраться до этой точки.


person DevB1    schedule 04.12.2019    source источник


Ответы (1)


Во-первых, вам не нужен SKVideoNode в SKScene в SCNNode. Вы можете напрямую использовать AVPlayer как диффузное содержимое вашего SCNNode: plane.firstMaterial?.diffuse.contents = player

Для зацикливания вы должны подписаться на уведомление на плеере и сбросить время до нуля в конце:

NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: nil) { _ in
    player.seek(to: .zero)
    player.play()
}
person ryancrunchi    schedule 04.12.2019
comment
Отлично, спасибо. Одна из проблем, с которой я сталкиваюсь, заключается в том, что я использую объект AVPlayer каждый раз, когда распознается изображение. Когда я добавляю наблюдателя, он запускает player.seek (to: .zero) только на первом распознанном изображении. Это странно, потому что я добавил оператор печати в это закрытие: print (Видео завершено), и он печатает каждый раз, когда заканчивается одно из трех видео, но он не запускает поиск до нуля более чем на одном ... - person DevB1; 04.12.2019
comment
Чтобы добавить немного больше, я добавил еще один оператор печати после print (видео завершено) следующим образом: print (VIDEO TITLE: (self.player.currentItem? .Asset)), и действительно, это всегда один и тот же элемент, который печатается, поэтому self .player здесь, кажется, всегда относится к первому воспроизведенному видео. Но тогда я смущен, почему в том же закрытии он успешно печатает `` Видео завершено '', когда другие видео заканчивают воспроизведение - person DevB1; 05.12.2019
comment
Итак, я подумал, что мне, очевидно, нужно иметь 3 отдельных AVPlayer (), чтобы управлять ими по отдельности - но теперь я, кажется, нахожусь в положении, когда все три видео сбрасываются до нуля и воспроизводятся снова после завершения первого видео ... кажется странным поскольку у меня есть 3 сценария, теперь обернутые в 3 отдельных оператора if, относящихся к имени распознанного изображения. - person DevB1; 05.12.2019