AVFoundation视频播放问题

时间:2019-03-22 14:11:13

标签: ios xcode avfoundation arkit

我一直跟着Yuma的this excellent tutorial一起工作,并且有一些工作要做。下面是我在viewcontroller中使用的代码

import UIKit
import SceneKit
import ARKit
import AVFoundation
import SpriteKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set the view's delegate
        sceneView.delegate = self

        // Show statistics such as fps and timing information
        sceneView.showsStatistics = true

        // Create a new scene
        let scene = SCNScene(named: "art.scnassets/notebook.scn")!

        // Set the scene to the view
        sceneView.scene = scene
    }

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

        // Create a session configuration
        let configuration = ARImageTrackingConfiguration()

        guard let arImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else { return }
        configuration.trackingImages = arImages
        // Run the view's session
        sceneView.session.run(configuration)
    }

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

        // Pause the view's session
        sceneView.session.pause()
    }
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard anchor is ARImageAnchor else { return }

        // Amy Image recognition
        guard let amyContainer = sceneView.scene.rootNode.childNode(withName: "amy", recursively: false) else { return }
        amyContainer.removeFromParentNode()
        node.addChildNode(amyContainer)
        amyContainer.isHidden = false

        // Video
        let videoURL = Bundle.main.url(forResource: "video", withExtension: "mp4")!

        let videoPlayer = AVPlayer(url: videoURL)

        let videoScene = SKScene(size: CGSize(width: 900.0, height: 1400.0))

        let videoNode = SKVideoNode(avPlayer: videoPlayer)

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

        videoNode.size = videoScene.size

        videoNode.yScale = -1

        videoNode.play()

        videoScene.addChild(videoNode)

        guard let video = amyContainer.childNode(withName: "video", recursively: true)
        else { return }
    video.geometry?.firstMaterial?.diffuse.contents = videoScene

 }
 }

当我使用教程中提供的视频时,一切都可以正常运行,但是当我尝试添加自己创建的视频时,只会在目标图像上出现一个白框,而没有视频。

我对名称进行了三倍检查,并尝试导出尺寸完全相同的视频,但都没有运气。我已经测试过上传一个新版本的视频,它确实可以使用不同的文件名并更改了名称,并且可以正常工作,所以我必须假设这是我正在制作的.mp4引起的。

这种方法对mp4是否有特定的规则/设置,我可以使用Premiere Pro或Handbrake中的设置吗?或者我该如何调试通过Xcode本身发生的任何内部错误?

2 个答案:

答案 0 :(得分:3)

可能是因为您的视频尺寸很大。您需要先等待 AVPlayer 准备就绪,然后再尝试播放视频

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!
    var observer: NSKeyValueObservation?
    var videoNode: SKVideoNode?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Set the view's delegate
        sceneView.delegate = self

        // Show statistics such as fps and timing information
        sceneView.showsStatistics = true

        // Create a new scene
        let scene = SCNScene(named: "art.scnassets/notebook.scn")!

        // Set the scene to the view
        sceneView.scene = scene
    }

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

        // Create a session configuration
        let configuration = ARImageTrackingConfiguration()

        guard let arImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else { return }
        configuration.trackingImages = arImages
        // Run the view's session
        sceneView.session.run(configuration)
    }

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

        // Pause the view's session
        sceneView.session.pause()
    }
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard anchor is ARImageAnchor else { return }

        // Amy Image recognition
        guard let amyContainer = sceneView.scene.rootNode.childNode(withName: "amy", recursively: false) else { return }
        amyContainer.removeFromParentNode()
        node.addChildNode(amyContainer)
        amyContainer.isHidden = false

        let videoPlayer = self.createAVPlayer()

        let videoScene = SKScene(size: CGSize(width: 900.0, height: 1400.0))

        self.videoNode = SKVideoNode(avPlayer: videoPlayer)

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

        self.videoNode?.size = videoScene.size

        self.videoNode?.yScale = -1

        videoScene.addChild(self.videoNode!)

        guard let video = amyContainer.childNode(withName: "video", recursively: true)
            else { return }
        video.geometry?.firstMaterial?.diffuse.contents = videoScene

    }

    func createAVPlayer() -> AVPlayer {
        let videoURL = Bundle.main.url(forResource: "video", withExtension: "mp4")!
        let asset = AVAsset(url: videoURL)

        let assetKeys = [
            "playable",
            "hasProtectedContent"
        ]
        let playerItem = AVPlayerItem(asset: asset,
                                      automaticallyLoadedAssetKeys: assetKeys)

        self.observer = playerItem.observe(\.status, options:  [.new, .old], changeHandler: { (playerItem, change) in
            if playerItem.status == .readyToPlay {

                self.videoNode?.play() // Only play when Its ready
            }
        })

        return AVPlayer(playerItem: playerItem)
    }
}

答案 1 :(得分:0)

我已经使用下面的代码正常播放了各种文件大小和比例的视频。

    let videoURL = URL(fileURLWithPath: Bundle.main.path(forResource: videoAssetName, ofType: videoAssetExtension)!)
    let player = AVPlayer(url: videoURL)
    player.actionAtItemEnd = .none
    videoPlayerNode = SKVideoNode(avPlayer: player)

    // setup player
    let skSceneSize = orientation == .horizontal ? CGSize(width: 1280, height: 720) : CGSize(width: 406, height: 720)
    let skScene = SKScene(size: skSceneSize)
    skScene.addChild(videoPlayerNode)

    videoPlayerNode.position = CGPoint(x: skScene.size.width/2, y: skScene.size.height/2)
    videoPlayerNode.size = skScene.size

    let scnPlaneSize : [String : CGFloat] = orientation == .horizontal ? ["width": 0.9, "height": 0.5063] : ["width": 0.5063, "height": 0.9]
    let videoPlane = SCNPlane(width: scnPlaneSize["width"]!, height: scnPlaneSize["height"]!)
    videoPlane.firstMaterial?.diffuse.contents = skScene
    videoPlane.firstMaterial?.isDoubleSided = true

    let videoPlaneNode = SCNNode(geometry: videoPlane)
    videoPlaneNode.eulerAngles = SCNVector3(180.degreesToRadians, 180.degreesToRadians, 0) // rotate video node to counter flip caused by contraint on adNode
    amyContainer.addChildNode(videoPlaneNode)

    // setup node to auto remove itself upon completion
    NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: player.currentItem, queue: nil, using: { (_) in
        DispatchQueue.main.async {
            // do something on video end
        }
    })