【问题标题】:Initializing SKVideoNode using AVPlayer object - SWIFT使用 AVPlayer 对象初始化 SKVideoNode - SWIFT
【发布时间】:2020-03-29 11:33:27
【问题描述】:

我正在使用 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() 但视频从不播放。相反,我的飞机只是在我的图像上显示为一个空白矩形。

一旦我成功初始化它,我想我可以添加一个观察者来检查视频何时播放完毕并重新启动它,但我很难达到这一点。

【问题讨论】:

    标签: ios swift avplayer skvideonode


    【解决方案1】:

    首先,您不需要在 SCNNode 中的 SKScene 中使用 SKVideoNode。您可以直接使用 AVPlayer 作为 SCNNode 的扩散内容: plane.firstMaterial?.diffuse.contents = player

    对于循环,您必须在播放器上订阅通知并在结束时将时间重置为零:

    NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: nil) { _ in
        player.seek(to: .zero)
        player.play()
    }
    

    【讨论】:

    • 非常感谢。我遇到的一个问题是每次识别图像时我都在使用 AVPlayer 对象。当我添加观察者时,它只在识别的第一张图像上运行 player.seek(to: .zero)。这很奇怪,因为我在该闭包中添加了一个打印语句: print("Video finished") 并且每次三个视频中的任何一个完成时都会打印,但它不会在多个视频上运行寻零...
    • 只是为了补充一点,我在 print("Video finished") 之后添加了另一个打印语句,如下所示: print("VIDEO TITLE: (self.player.currentItem?.asset)") 和事实上,它总是打印相同的项目,所以这里的 self.player 似乎总是指的是第一个播放的视频。但我很困惑,为什么在同一个闭包中,当其他视频播放完毕时,它会成功打印“视频完成”
    • 所以我想我显然需要有 3 个单独的 AVPlayers() 才能单独控制它们 - 但现在我似乎处于一个位置,所有三个视频都重置为零并在第一个视频结束......看起来很奇怪,因为我现在有 3 个场景包含在 3 个单独的 if 语句中,这些语句与识别的图像名称有关。
    猜你喜欢
    • 2013-06-27
    • 2014-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    • 1970-01-01
    相关资源
    最近更新 更多