ARKit SKVideoNode Playing on Render










32














Main Problem:



I am adding this section AFTER to clarify the problem. -- I can PAUSE my video (I do not want it playing on a loop). When my node comes into sight, my node plays my video, even if it is on pause. If my video has finished playing, and it comes into sight, it will restart. I want to REMOVE this behavior.



In my app, I have a SKVideoNode created from an AVPlayer(:URL) inside 3D Space using SCNNode objects and SCNGeometry objects. I use ARKit .ImageTracking to determine when a specific image is found, and play a video from there. All is good and dandy, except that the player determines to play on its own time, every time the AVPlayer comes into sight; however, it could be whenever the ARImageAnchor the SCNNode is attached to comes into sight. Either way, the AVPlayer is playing every time the node comes into sight of the camera lens. I use



override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 
if(keyPath == "rate")
print((object as! AVPlayer).rate)




to print out the rate, and it is 1, however, it was 0.



I printed out some sort of print function print("Play") for all of my functions utilizing player.pause() or player.play() and none of them are called whenever the rate is changed above. How can I find the source of what is changing the rate of my player?



I checked the original rootnode, self.sceneview.scene.rootNode.childNodes to make sure I am not creating extra VideoNodes/SCNNodes/AVPlayers, etc, and it seems that there is only 1.



Any ideas on why the SKVideoNode/AVPlayer is playing as the SCNNode comes into sight of the camera using ARKit? Thanks in advance!



Edit1:



Made a workaround, to determine ONLY when a user clicked on this node



let tap = UITapGestureRecognizer(target: self, action: #selector(self!.tapGesture))
tap.delegate = self!
tap.name = "MyTap"
self!.sceneView.addGestureRecognizer(tap)


and then inside of this next function, I put



@objc func tapGesture(_ gesture:UITapGestureRecognizer) 
let tappedNodes = self.sceneView.hitTest(gesture.location(in: gesture.view), options: [SCNHitTestOption.searchMode: 1])

if !tappedNodes.isEmpty
for nodes in tappedNodes
if nodes.node == videoPlayer3D
videoPlayer3D.tappedVideoPlayer = true
videoPlayer3D.playOrPause()
break





override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
if(keyPath == "rate")
print((object as! AVPlayer).rate)
if(!self.tappedVideoPlayer)
self.player.pause() //HERE





where videoPlayer3D is the SCNNode that contains the SKVideoNode.



However, I get the error com.apple.scenekit.scnview-renderer (17): EXC_BAD_ACCESS (code=2, address=0x16d8f7ad0) on the section labeled "HERE" above. It seems that the renderer of the sceneview is attempting to alter my video node in the render function, although, I don't even use the renderer(updateAtTime:) function, I only use



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)




to determine when I see an image, i.e., imageTracking and I create the node. Any tips?



Thought 1



The error is presented stating that some method is being called from an SCNView object for the method renderer (that's what I'm understanding from the error), but I don't have the node specifically called. I think maybe a default action, as the node is coming to view, is being called, however, I'm not 100% sure on how to access it or determine which method. The objects I'm using are not SCNView objects, and I don't believe they inherit from SCNView objects (look at the 1st paragraph to see the variables used). Just looking to remove the "action" of the node playing every time it is in view.



ADDITION:



For the sake of following the creation of my video player if interested, here it is. Let me know if there is anything else you'd like to see (not sure what else you might want to see) and thanks for your help.



func createVideoNode(_ anchor:ARImageAnchor, initialPOV:SCNNode) -> My3DPlayer? 

guard let currentFrame = self.sceneView.session.currentFrame else
return nil


let delegate = UIApplication.shared.delegate as! AppDelegate

var videoPlayer:My3DPlayer!
videoPlayer = delegate.testing ? My3DPlayer(data: nil, currentFrame: currentFrame, anchor: anchor) : My3DPlayer(data: self.urlData, currentFrame: currentFrame, anchor: anchor)

//Create TapGesture
let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture))
tap.delegate = self
tap.name = "MyTap"
self.sceneView.addGestureRecognizer(tap)

return videoPlayer



My3dPlayer Class:



class My3DPlayer: SCNNode 

init(geometry: SCNGeometry?)
super.init()
self.geometry = geometry


required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")


convenience init(data:Data?, currentFrame:ARFrame, anchor:ARImageAnchor)
self.init(geometry: nil)
self.createPlayer(currentFrame, data, anchor)


private func createPlayer(_ frame:ARFrame, _ data:Data?,_ anchor:ARImageAnchor)

let physicalSize = anchor.referenceImage.physicalSize

print("Init Player W/ physicalSize: (physicalSize)")

//Create video
if((UIApplication.shared.delegate! as! AppDelegate).testing)
let path = Bundle.main.path(forResource: "Bear", ofType: "mov")
self.url = URL(fileURLWithPath: path!)

else
let url = data!.getAVAssetURL(location: "MyLocation")
self.url = url

let asset = AVAsset(url: self.url)
let track = asset.tracks(withMediaType: AVMediaType.video).first!
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
self.player = player
var videoSize = track.naturalSize.applying(track.preferredTransform)

videoSize = CGSize(width: abs(videoSize.width), height: abs(videoSize.height))
print("Init Video W/ size: (videoSize)")

//Determine if landscape or portrait
self.landscape = videoSize.width > videoSize.height
print(self.landscape == true ? "Landscape" : "Portrait")

//Do something when video ended
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(note:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)

//Add observer to determine when Player is ready
player.addObserver(self, forKeyPath: "status", options: , context: nil)

//Create video Node
let videoNode = SKVideoNode(avPlayer: player)

//Create 2d scene to put 2d player on - SKScene
videoNode.position = CGPoint(x: videoSize.width/2, y: videoSize.height/2)
videoNode.size = videoSize


//Portrait -- //Landscape doesn't need adjustments??
if(!self.landscape)
let width = videoNode.size.width
videoNode.size.width = videoNode.size.height
videoNode.size.height = width
videoNode.position = CGPoint(x: videoNode.size.width/2, y: videoNode.size.height/2)


let scene = SKScene(size: videoNode.size)

//Add videoNode to scene
scene.addChild(videoNode)

//Create Button-look even though we don't use the button. Just creates the illusion to pressing play and pause
let image = UIImage(named: "PlayButton")!
let texture = SKTexture(image: image)
self.button = SKSpriteNode(texture: texture)
self.button.position = videoNode.position

//Makes the button look like a square
let minimumSize = [videoSize.width, videoSize.height].min()!
self.button.size = CGSize(width: minimumSize/4, height: minimumSize/4)
scene.addChild(button)

//Get ratio difference from physicalsize and video size
let widthRatio = Float(physicalSize.width)/Float(videoSize.width)
let heightRatio = Float(physicalSize.height)/Float(videoSize.height)

let finalRatio = [widthRatio, heightRatio].min()!

//Create a Plane (SCNPlane) to put the SKScene on
let plane = SCNPlane(width: scene.size.width, height: scene.size.height)
plane.firstMaterial?.diffuse.contents = scene
plane.firstMaterial?.isDoubleSided = true

//Set Self.geometry = plane
self.geometry = plane

//Size the node correctly
//Find the real scaling variable
let scale = CGFloat(finalRatio)
let appearanceAction = SCNAction.scale(to: scale, duration: 0.4)
appearanceAction.timingMode = .easeOut

//Set initial scale to 0 then use action to scale up
self.scale = SCNVector3Make(0, 0, 0)
self.runAction(appearanceAction)


@objc func playerDidFinishPlaying(note: Notification)
self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
self.setButtonAlpha(alpha: 1)




Efforts1:



I have tried to stop tracking via:



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)
self.resetConfiguration(turnOnConfig: true, turnOnImageTracking: false)


func resetConfiguration(turnOnConfig: Bool = true, turnOnImageTracking:Bool = false)
let configuration = ARWorldTrackingConfiguration()
if(turnOnImageTracking)
guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else
fatalError("Missing expected asset catalog resources.")

configuration.planeDetection = .horizontal
configuration.detectionImages = referenceImages

else
configuration.planeDetection =

if(turnOnConfig)
sceneView.session.run(configuration, options: [.resetTracking])




Above, I have tried to reset the configuration. This only causes it to reset the planes it seems, as the video is still playing on render. Whether it is paused or finished, it will reset and start over or continue playing where left off.



Efforts2:



I have tried



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)
self.pauseTracking()


func pauseTracking()
self.sceneView.session.pause()



This stops everything therefore the camera even freezes as nothing is being tracked. It is completely useless here.










share|improve this question























  • can we see createVideoNode plz. Normally we add video node as child of node in didAdd node.
    – Alok Subedi
    Dec 24 '18 at 5:48










  • How does the creation of where I add my node affect that my video be played every time it comes to view? Even if it is on pause.
    – impression7vx
    Dec 24 '18 at 16:01











  • Not sure , just my guess, there must be some logical issue if it plays everytime imageAnchor is found.
    – Alok Subedi
    Dec 25 '18 at 4:41










  • I added it for kicks and giggles
    – impression7vx
    Jan 1 at 20:11










  • Where's the code for your ARWorldTrackingConfiguration used here? Would it be an option for you to stop the 'detection' once the video started playing?
    – Mihai Erős
    Jan 4 at 16:27















32














Main Problem:



I am adding this section AFTER to clarify the problem. -- I can PAUSE my video (I do not want it playing on a loop). When my node comes into sight, my node plays my video, even if it is on pause. If my video has finished playing, and it comes into sight, it will restart. I want to REMOVE this behavior.



In my app, I have a SKVideoNode created from an AVPlayer(:URL) inside 3D Space using SCNNode objects and SCNGeometry objects. I use ARKit .ImageTracking to determine when a specific image is found, and play a video from there. All is good and dandy, except that the player determines to play on its own time, every time the AVPlayer comes into sight; however, it could be whenever the ARImageAnchor the SCNNode is attached to comes into sight. Either way, the AVPlayer is playing every time the node comes into sight of the camera lens. I use



override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 
if(keyPath == "rate")
print((object as! AVPlayer).rate)




to print out the rate, and it is 1, however, it was 0.



I printed out some sort of print function print("Play") for all of my functions utilizing player.pause() or player.play() and none of them are called whenever the rate is changed above. How can I find the source of what is changing the rate of my player?



I checked the original rootnode, self.sceneview.scene.rootNode.childNodes to make sure I am not creating extra VideoNodes/SCNNodes/AVPlayers, etc, and it seems that there is only 1.



Any ideas on why the SKVideoNode/AVPlayer is playing as the SCNNode comes into sight of the camera using ARKit? Thanks in advance!



Edit1:



Made a workaround, to determine ONLY when a user clicked on this node



let tap = UITapGestureRecognizer(target: self, action: #selector(self!.tapGesture))
tap.delegate = self!
tap.name = "MyTap"
self!.sceneView.addGestureRecognizer(tap)


and then inside of this next function, I put



@objc func tapGesture(_ gesture:UITapGestureRecognizer) 
let tappedNodes = self.sceneView.hitTest(gesture.location(in: gesture.view), options: [SCNHitTestOption.searchMode: 1])

if !tappedNodes.isEmpty
for nodes in tappedNodes
if nodes.node == videoPlayer3D
videoPlayer3D.tappedVideoPlayer = true
videoPlayer3D.playOrPause()
break





override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
if(keyPath == "rate")
print((object as! AVPlayer).rate)
if(!self.tappedVideoPlayer)
self.player.pause() //HERE





where videoPlayer3D is the SCNNode that contains the SKVideoNode.



However, I get the error com.apple.scenekit.scnview-renderer (17): EXC_BAD_ACCESS (code=2, address=0x16d8f7ad0) on the section labeled "HERE" above. It seems that the renderer of the sceneview is attempting to alter my video node in the render function, although, I don't even use the renderer(updateAtTime:) function, I only use



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)




to determine when I see an image, i.e., imageTracking and I create the node. Any tips?



Thought 1



The error is presented stating that some method is being called from an SCNView object for the method renderer (that's what I'm understanding from the error), but I don't have the node specifically called. I think maybe a default action, as the node is coming to view, is being called, however, I'm not 100% sure on how to access it or determine which method. The objects I'm using are not SCNView objects, and I don't believe they inherit from SCNView objects (look at the 1st paragraph to see the variables used). Just looking to remove the "action" of the node playing every time it is in view.



ADDITION:



For the sake of following the creation of my video player if interested, here it is. Let me know if there is anything else you'd like to see (not sure what else you might want to see) and thanks for your help.



func createVideoNode(_ anchor:ARImageAnchor, initialPOV:SCNNode) -> My3DPlayer? 

guard let currentFrame = self.sceneView.session.currentFrame else
return nil


let delegate = UIApplication.shared.delegate as! AppDelegate

var videoPlayer:My3DPlayer!
videoPlayer = delegate.testing ? My3DPlayer(data: nil, currentFrame: currentFrame, anchor: anchor) : My3DPlayer(data: self.urlData, currentFrame: currentFrame, anchor: anchor)

//Create TapGesture
let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture))
tap.delegate = self
tap.name = "MyTap"
self.sceneView.addGestureRecognizer(tap)

return videoPlayer



My3dPlayer Class:



class My3DPlayer: SCNNode 

init(geometry: SCNGeometry?)
super.init()
self.geometry = geometry


required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")


convenience init(data:Data?, currentFrame:ARFrame, anchor:ARImageAnchor)
self.init(geometry: nil)
self.createPlayer(currentFrame, data, anchor)


private func createPlayer(_ frame:ARFrame, _ data:Data?,_ anchor:ARImageAnchor)

let physicalSize = anchor.referenceImage.physicalSize

print("Init Player W/ physicalSize: (physicalSize)")

//Create video
if((UIApplication.shared.delegate! as! AppDelegate).testing)
let path = Bundle.main.path(forResource: "Bear", ofType: "mov")
self.url = URL(fileURLWithPath: path!)

else
let url = data!.getAVAssetURL(location: "MyLocation")
self.url = url

let asset = AVAsset(url: self.url)
let track = asset.tracks(withMediaType: AVMediaType.video).first!
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
self.player = player
var videoSize = track.naturalSize.applying(track.preferredTransform)

videoSize = CGSize(width: abs(videoSize.width), height: abs(videoSize.height))
print("Init Video W/ size: (videoSize)")

//Determine if landscape or portrait
self.landscape = videoSize.width > videoSize.height
print(self.landscape == true ? "Landscape" : "Portrait")

//Do something when video ended
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(note:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)

//Add observer to determine when Player is ready
player.addObserver(self, forKeyPath: "status", options: , context: nil)

//Create video Node
let videoNode = SKVideoNode(avPlayer: player)

//Create 2d scene to put 2d player on - SKScene
videoNode.position = CGPoint(x: videoSize.width/2, y: videoSize.height/2)
videoNode.size = videoSize


//Portrait -- //Landscape doesn't need adjustments??
if(!self.landscape)
let width = videoNode.size.width
videoNode.size.width = videoNode.size.height
videoNode.size.height = width
videoNode.position = CGPoint(x: videoNode.size.width/2, y: videoNode.size.height/2)


let scene = SKScene(size: videoNode.size)

//Add videoNode to scene
scene.addChild(videoNode)

//Create Button-look even though we don't use the button. Just creates the illusion to pressing play and pause
let image = UIImage(named: "PlayButton")!
let texture = SKTexture(image: image)
self.button = SKSpriteNode(texture: texture)
self.button.position = videoNode.position

//Makes the button look like a square
let minimumSize = [videoSize.width, videoSize.height].min()!
self.button.size = CGSize(width: minimumSize/4, height: minimumSize/4)
scene.addChild(button)

//Get ratio difference from physicalsize and video size
let widthRatio = Float(physicalSize.width)/Float(videoSize.width)
let heightRatio = Float(physicalSize.height)/Float(videoSize.height)

let finalRatio = [widthRatio, heightRatio].min()!

//Create a Plane (SCNPlane) to put the SKScene on
let plane = SCNPlane(width: scene.size.width, height: scene.size.height)
plane.firstMaterial?.diffuse.contents = scene
plane.firstMaterial?.isDoubleSided = true

//Set Self.geometry = plane
self.geometry = plane

//Size the node correctly
//Find the real scaling variable
let scale = CGFloat(finalRatio)
let appearanceAction = SCNAction.scale(to: scale, duration: 0.4)
appearanceAction.timingMode = .easeOut

//Set initial scale to 0 then use action to scale up
self.scale = SCNVector3Make(0, 0, 0)
self.runAction(appearanceAction)


@objc func playerDidFinishPlaying(note: Notification)
self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
self.setButtonAlpha(alpha: 1)




Efforts1:



I have tried to stop tracking via:



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)
self.resetConfiguration(turnOnConfig: true, turnOnImageTracking: false)


func resetConfiguration(turnOnConfig: Bool = true, turnOnImageTracking:Bool = false)
let configuration = ARWorldTrackingConfiguration()
if(turnOnImageTracking)
guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else
fatalError("Missing expected asset catalog resources.")

configuration.planeDetection = .horizontal
configuration.detectionImages = referenceImages

else
configuration.planeDetection =

if(turnOnConfig)
sceneView.session.run(configuration, options: [.resetTracking])




Above, I have tried to reset the configuration. This only causes it to reset the planes it seems, as the video is still playing on render. Whether it is paused or finished, it will reset and start over or continue playing where left off.



Efforts2:



I have tried



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)
self.pauseTracking()


func pauseTracking()
self.sceneView.session.pause()



This stops everything therefore the camera even freezes as nothing is being tracked. It is completely useless here.










share|improve this question























  • can we see createVideoNode plz. Normally we add video node as child of node in didAdd node.
    – Alok Subedi
    Dec 24 '18 at 5:48










  • How does the creation of where I add my node affect that my video be played every time it comes to view? Even if it is on pause.
    – impression7vx
    Dec 24 '18 at 16:01











  • Not sure , just my guess, there must be some logical issue if it plays everytime imageAnchor is found.
    – Alok Subedi
    Dec 25 '18 at 4:41










  • I added it for kicks and giggles
    – impression7vx
    Jan 1 at 20:11










  • Where's the code for your ARWorldTrackingConfiguration used here? Would it be an option for you to stop the 'detection' once the video started playing?
    – Mihai Erős
    Jan 4 at 16:27













32












32








32


3





Main Problem:



I am adding this section AFTER to clarify the problem. -- I can PAUSE my video (I do not want it playing on a loop). When my node comes into sight, my node plays my video, even if it is on pause. If my video has finished playing, and it comes into sight, it will restart. I want to REMOVE this behavior.



In my app, I have a SKVideoNode created from an AVPlayer(:URL) inside 3D Space using SCNNode objects and SCNGeometry objects. I use ARKit .ImageTracking to determine when a specific image is found, and play a video from there. All is good and dandy, except that the player determines to play on its own time, every time the AVPlayer comes into sight; however, it could be whenever the ARImageAnchor the SCNNode is attached to comes into sight. Either way, the AVPlayer is playing every time the node comes into sight of the camera lens. I use



override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 
if(keyPath == "rate")
print((object as! AVPlayer).rate)




to print out the rate, and it is 1, however, it was 0.



I printed out some sort of print function print("Play") for all of my functions utilizing player.pause() or player.play() and none of them are called whenever the rate is changed above. How can I find the source of what is changing the rate of my player?



I checked the original rootnode, self.sceneview.scene.rootNode.childNodes to make sure I am not creating extra VideoNodes/SCNNodes/AVPlayers, etc, and it seems that there is only 1.



Any ideas on why the SKVideoNode/AVPlayer is playing as the SCNNode comes into sight of the camera using ARKit? Thanks in advance!



Edit1:



Made a workaround, to determine ONLY when a user clicked on this node



let tap = UITapGestureRecognizer(target: self, action: #selector(self!.tapGesture))
tap.delegate = self!
tap.name = "MyTap"
self!.sceneView.addGestureRecognizer(tap)


and then inside of this next function, I put



@objc func tapGesture(_ gesture:UITapGestureRecognizer) 
let tappedNodes = self.sceneView.hitTest(gesture.location(in: gesture.view), options: [SCNHitTestOption.searchMode: 1])

if !tappedNodes.isEmpty
for nodes in tappedNodes
if nodes.node == videoPlayer3D
videoPlayer3D.tappedVideoPlayer = true
videoPlayer3D.playOrPause()
break





override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
if(keyPath == "rate")
print((object as! AVPlayer).rate)
if(!self.tappedVideoPlayer)
self.player.pause() //HERE





where videoPlayer3D is the SCNNode that contains the SKVideoNode.



However, I get the error com.apple.scenekit.scnview-renderer (17): EXC_BAD_ACCESS (code=2, address=0x16d8f7ad0) on the section labeled "HERE" above. It seems that the renderer of the sceneview is attempting to alter my video node in the render function, although, I don't even use the renderer(updateAtTime:) function, I only use



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)




to determine when I see an image, i.e., imageTracking and I create the node. Any tips?



Thought 1



The error is presented stating that some method is being called from an SCNView object for the method renderer (that's what I'm understanding from the error), but I don't have the node specifically called. I think maybe a default action, as the node is coming to view, is being called, however, I'm not 100% sure on how to access it or determine which method. The objects I'm using are not SCNView objects, and I don't believe they inherit from SCNView objects (look at the 1st paragraph to see the variables used). Just looking to remove the "action" of the node playing every time it is in view.



ADDITION:



For the sake of following the creation of my video player if interested, here it is. Let me know if there is anything else you'd like to see (not sure what else you might want to see) and thanks for your help.



func createVideoNode(_ anchor:ARImageAnchor, initialPOV:SCNNode) -> My3DPlayer? 

guard let currentFrame = self.sceneView.session.currentFrame else
return nil


let delegate = UIApplication.shared.delegate as! AppDelegate

var videoPlayer:My3DPlayer!
videoPlayer = delegate.testing ? My3DPlayer(data: nil, currentFrame: currentFrame, anchor: anchor) : My3DPlayer(data: self.urlData, currentFrame: currentFrame, anchor: anchor)

//Create TapGesture
let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture))
tap.delegate = self
tap.name = "MyTap"
self.sceneView.addGestureRecognizer(tap)

return videoPlayer



My3dPlayer Class:



class My3DPlayer: SCNNode 

init(geometry: SCNGeometry?)
super.init()
self.geometry = geometry


required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")


convenience init(data:Data?, currentFrame:ARFrame, anchor:ARImageAnchor)
self.init(geometry: nil)
self.createPlayer(currentFrame, data, anchor)


private func createPlayer(_ frame:ARFrame, _ data:Data?,_ anchor:ARImageAnchor)

let physicalSize = anchor.referenceImage.physicalSize

print("Init Player W/ physicalSize: (physicalSize)")

//Create video
if((UIApplication.shared.delegate! as! AppDelegate).testing)
let path = Bundle.main.path(forResource: "Bear", ofType: "mov")
self.url = URL(fileURLWithPath: path!)

else
let url = data!.getAVAssetURL(location: "MyLocation")
self.url = url

let asset = AVAsset(url: self.url)
let track = asset.tracks(withMediaType: AVMediaType.video).first!
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
self.player = player
var videoSize = track.naturalSize.applying(track.preferredTransform)

videoSize = CGSize(width: abs(videoSize.width), height: abs(videoSize.height))
print("Init Video W/ size: (videoSize)")

//Determine if landscape or portrait
self.landscape = videoSize.width > videoSize.height
print(self.landscape == true ? "Landscape" : "Portrait")

//Do something when video ended
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(note:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)

//Add observer to determine when Player is ready
player.addObserver(self, forKeyPath: "status", options: , context: nil)

//Create video Node
let videoNode = SKVideoNode(avPlayer: player)

//Create 2d scene to put 2d player on - SKScene
videoNode.position = CGPoint(x: videoSize.width/2, y: videoSize.height/2)
videoNode.size = videoSize


//Portrait -- //Landscape doesn't need adjustments??
if(!self.landscape)
let width = videoNode.size.width
videoNode.size.width = videoNode.size.height
videoNode.size.height = width
videoNode.position = CGPoint(x: videoNode.size.width/2, y: videoNode.size.height/2)


let scene = SKScene(size: videoNode.size)

//Add videoNode to scene
scene.addChild(videoNode)

//Create Button-look even though we don't use the button. Just creates the illusion to pressing play and pause
let image = UIImage(named: "PlayButton")!
let texture = SKTexture(image: image)
self.button = SKSpriteNode(texture: texture)
self.button.position = videoNode.position

//Makes the button look like a square
let minimumSize = [videoSize.width, videoSize.height].min()!
self.button.size = CGSize(width: minimumSize/4, height: minimumSize/4)
scene.addChild(button)

//Get ratio difference from physicalsize and video size
let widthRatio = Float(physicalSize.width)/Float(videoSize.width)
let heightRatio = Float(physicalSize.height)/Float(videoSize.height)

let finalRatio = [widthRatio, heightRatio].min()!

//Create a Plane (SCNPlane) to put the SKScene on
let plane = SCNPlane(width: scene.size.width, height: scene.size.height)
plane.firstMaterial?.diffuse.contents = scene
plane.firstMaterial?.isDoubleSided = true

//Set Self.geometry = plane
self.geometry = plane

//Size the node correctly
//Find the real scaling variable
let scale = CGFloat(finalRatio)
let appearanceAction = SCNAction.scale(to: scale, duration: 0.4)
appearanceAction.timingMode = .easeOut

//Set initial scale to 0 then use action to scale up
self.scale = SCNVector3Make(0, 0, 0)
self.runAction(appearanceAction)


@objc func playerDidFinishPlaying(note: Notification)
self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
self.setButtonAlpha(alpha: 1)




Efforts1:



I have tried to stop tracking via:



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)
self.resetConfiguration(turnOnConfig: true, turnOnImageTracking: false)


func resetConfiguration(turnOnConfig: Bool = true, turnOnImageTracking:Bool = false)
let configuration = ARWorldTrackingConfiguration()
if(turnOnImageTracking)
guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else
fatalError("Missing expected asset catalog resources.")

configuration.planeDetection = .horizontal
configuration.detectionImages = referenceImages

else
configuration.planeDetection =

if(turnOnConfig)
sceneView.session.run(configuration, options: [.resetTracking])




Above, I have tried to reset the configuration. This only causes it to reset the planes it seems, as the video is still playing on render. Whether it is paused or finished, it will reset and start over or continue playing where left off.



Efforts2:



I have tried



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)
self.pauseTracking()


func pauseTracking()
self.sceneView.session.pause()



This stops everything therefore the camera even freezes as nothing is being tracked. It is completely useless here.










share|improve this question















Main Problem:



I am adding this section AFTER to clarify the problem. -- I can PAUSE my video (I do not want it playing on a loop). When my node comes into sight, my node plays my video, even if it is on pause. If my video has finished playing, and it comes into sight, it will restart. I want to REMOVE this behavior.



In my app, I have a SKVideoNode created from an AVPlayer(:URL) inside 3D Space using SCNNode objects and SCNGeometry objects. I use ARKit .ImageTracking to determine when a specific image is found, and play a video from there. All is good and dandy, except that the player determines to play on its own time, every time the AVPlayer comes into sight; however, it could be whenever the ARImageAnchor the SCNNode is attached to comes into sight. Either way, the AVPlayer is playing every time the node comes into sight of the camera lens. I use



override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 
if(keyPath == "rate")
print((object as! AVPlayer).rate)




to print out the rate, and it is 1, however, it was 0.



I printed out some sort of print function print("Play") for all of my functions utilizing player.pause() or player.play() and none of them are called whenever the rate is changed above. How can I find the source of what is changing the rate of my player?



I checked the original rootnode, self.sceneview.scene.rootNode.childNodes to make sure I am not creating extra VideoNodes/SCNNodes/AVPlayers, etc, and it seems that there is only 1.



Any ideas on why the SKVideoNode/AVPlayer is playing as the SCNNode comes into sight of the camera using ARKit? Thanks in advance!



Edit1:



Made a workaround, to determine ONLY when a user clicked on this node



let tap = UITapGestureRecognizer(target: self, action: #selector(self!.tapGesture))
tap.delegate = self!
tap.name = "MyTap"
self!.sceneView.addGestureRecognizer(tap)


and then inside of this next function, I put



@objc func tapGesture(_ gesture:UITapGestureRecognizer) 
let tappedNodes = self.sceneView.hitTest(gesture.location(in: gesture.view), options: [SCNHitTestOption.searchMode: 1])

if !tappedNodes.isEmpty
for nodes in tappedNodes
if nodes.node == videoPlayer3D
videoPlayer3D.tappedVideoPlayer = true
videoPlayer3D.playOrPause()
break





override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
if(keyPath == "rate")
print((object as! AVPlayer).rate)
if(!self.tappedVideoPlayer)
self.player.pause() //HERE





where videoPlayer3D is the SCNNode that contains the SKVideoNode.



However, I get the error com.apple.scenekit.scnview-renderer (17): EXC_BAD_ACCESS (code=2, address=0x16d8f7ad0) on the section labeled "HERE" above. It seems that the renderer of the sceneview is attempting to alter my video node in the render function, although, I don't even use the renderer(updateAtTime:) function, I only use



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)




to determine when I see an image, i.e., imageTracking and I create the node. Any tips?



Thought 1



The error is presented stating that some method is being called from an SCNView object for the method renderer (that's what I'm understanding from the error), but I don't have the node specifically called. I think maybe a default action, as the node is coming to view, is being called, however, I'm not 100% sure on how to access it or determine which method. The objects I'm using are not SCNView objects, and I don't believe they inherit from SCNView objects (look at the 1st paragraph to see the variables used). Just looking to remove the "action" of the node playing every time it is in view.



ADDITION:



For the sake of following the creation of my video player if interested, here it is. Let me know if there is anything else you'd like to see (not sure what else you might want to see) and thanks for your help.



func createVideoNode(_ anchor:ARImageAnchor, initialPOV:SCNNode) -> My3DPlayer? 

guard let currentFrame = self.sceneView.session.currentFrame else
return nil


let delegate = UIApplication.shared.delegate as! AppDelegate

var videoPlayer:My3DPlayer!
videoPlayer = delegate.testing ? My3DPlayer(data: nil, currentFrame: currentFrame, anchor: anchor) : My3DPlayer(data: self.urlData, currentFrame: currentFrame, anchor: anchor)

//Create TapGesture
let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture))
tap.delegate = self
tap.name = "MyTap"
self.sceneView.addGestureRecognizer(tap)

return videoPlayer



My3dPlayer Class:



class My3DPlayer: SCNNode 

init(geometry: SCNGeometry?)
super.init()
self.geometry = geometry


required init?(coder aDecoder: NSCoder)
fatalError("init(coder:) has not been implemented")


convenience init(data:Data?, currentFrame:ARFrame, anchor:ARImageAnchor)
self.init(geometry: nil)
self.createPlayer(currentFrame, data, anchor)


private func createPlayer(_ frame:ARFrame, _ data:Data?,_ anchor:ARImageAnchor)

let physicalSize = anchor.referenceImage.physicalSize

print("Init Player W/ physicalSize: (physicalSize)")

//Create video
if((UIApplication.shared.delegate! as! AppDelegate).testing)
let path = Bundle.main.path(forResource: "Bear", ofType: "mov")
self.url = URL(fileURLWithPath: path!)

else
let url = data!.getAVAssetURL(location: "MyLocation")
self.url = url

let asset = AVAsset(url: self.url)
let track = asset.tracks(withMediaType: AVMediaType.video).first!
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
self.player = player
var videoSize = track.naturalSize.applying(track.preferredTransform)

videoSize = CGSize(width: abs(videoSize.width), height: abs(videoSize.height))
print("Init Video W/ size: (videoSize)")

//Determine if landscape or portrait
self.landscape = videoSize.width > videoSize.height
print(self.landscape == true ? "Landscape" : "Portrait")

//Do something when video ended
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(note:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)

//Add observer to determine when Player is ready
player.addObserver(self, forKeyPath: "status", options: , context: nil)

//Create video Node
let videoNode = SKVideoNode(avPlayer: player)

//Create 2d scene to put 2d player on - SKScene
videoNode.position = CGPoint(x: videoSize.width/2, y: videoSize.height/2)
videoNode.size = videoSize


//Portrait -- //Landscape doesn't need adjustments??
if(!self.landscape)
let width = videoNode.size.width
videoNode.size.width = videoNode.size.height
videoNode.size.height = width
videoNode.position = CGPoint(x: videoNode.size.width/2, y: videoNode.size.height/2)


let scene = SKScene(size: videoNode.size)

//Add videoNode to scene
scene.addChild(videoNode)

//Create Button-look even though we don't use the button. Just creates the illusion to pressing play and pause
let image = UIImage(named: "PlayButton")!
let texture = SKTexture(image: image)
self.button = SKSpriteNode(texture: texture)
self.button.position = videoNode.position

//Makes the button look like a square
let minimumSize = [videoSize.width, videoSize.height].min()!
self.button.size = CGSize(width: minimumSize/4, height: minimumSize/4)
scene.addChild(button)

//Get ratio difference from physicalsize and video size
let widthRatio = Float(physicalSize.width)/Float(videoSize.width)
let heightRatio = Float(physicalSize.height)/Float(videoSize.height)

let finalRatio = [widthRatio, heightRatio].min()!

//Create a Plane (SCNPlane) to put the SKScene on
let plane = SCNPlane(width: scene.size.width, height: scene.size.height)
plane.firstMaterial?.diffuse.contents = scene
plane.firstMaterial?.isDoubleSided = true

//Set Self.geometry = plane
self.geometry = plane

//Size the node correctly
//Find the real scaling variable
let scale = CGFloat(finalRatio)
let appearanceAction = SCNAction.scale(to: scale, duration: 0.4)
appearanceAction.timingMode = .easeOut

//Set initial scale to 0 then use action to scale up
self.scale = SCNVector3Make(0, 0, 0)
self.runAction(appearanceAction)


@objc func playerDidFinishPlaying(note: Notification)
self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
self.setButtonAlpha(alpha: 1)




Efforts1:



I have tried to stop tracking via:



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)
self.resetConfiguration(turnOnConfig: true, turnOnImageTracking: false)


func resetConfiguration(turnOnConfig: Bool = true, turnOnImageTracking:Bool = false)
let configuration = ARWorldTrackingConfiguration()
if(turnOnImageTracking)
guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else
fatalError("Missing expected asset catalog resources.")

configuration.planeDetection = .horizontal
configuration.detectionImages = referenceImages

else
configuration.planeDetection =

if(turnOnConfig)
sceneView.session.run(configuration, options: [.resetTracking])




Above, I have tried to reset the configuration. This only causes it to reset the planes it seems, as the video is still playing on render. Whether it is paused or finished, it will reset and start over or continue playing where left off.



Efforts2:



I have tried



func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 

guard let imageAnchor = anchor as? ARImageAnchor else return

createVideoNode(imageAnchor)
self.pauseTracking()


func pauseTracking()
self.sceneView.session.pause()



This stops everything therefore the camera even freezes as nothing is being tracked. It is completely useless here.







swift avplayer arkit scnnode skvideonode






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago







impression7vx

















asked Nov 12 '18 at 6:01









impression7vximpression7vx

2671836




2671836











  • can we see createVideoNode plz. Normally we add video node as child of node in didAdd node.
    – Alok Subedi
    Dec 24 '18 at 5:48










  • How does the creation of where I add my node affect that my video be played every time it comes to view? Even if it is on pause.
    – impression7vx
    Dec 24 '18 at 16:01











  • Not sure , just my guess, there must be some logical issue if it plays everytime imageAnchor is found.
    – Alok Subedi
    Dec 25 '18 at 4:41










  • I added it for kicks and giggles
    – impression7vx
    Jan 1 at 20:11










  • Where's the code for your ARWorldTrackingConfiguration used here? Would it be an option for you to stop the 'detection' once the video started playing?
    – Mihai Erős
    Jan 4 at 16:27
















  • can we see createVideoNode plz. Normally we add video node as child of node in didAdd node.
    – Alok Subedi
    Dec 24 '18 at 5:48










  • How does the creation of where I add my node affect that my video be played every time it comes to view? Even if it is on pause.
    – impression7vx
    Dec 24 '18 at 16:01











  • Not sure , just my guess, there must be some logical issue if it plays everytime imageAnchor is found.
    – Alok Subedi
    Dec 25 '18 at 4:41










  • I added it for kicks and giggles
    – impression7vx
    Jan 1 at 20:11










  • Where's the code for your ARWorldTrackingConfiguration used here? Would it be an option for you to stop the 'detection' once the video started playing?
    – Mihai Erős
    Jan 4 at 16:27















can we see createVideoNode plz. Normally we add video node as child of node in didAdd node.
– Alok Subedi
Dec 24 '18 at 5:48




can we see createVideoNode plz. Normally we add video node as child of node in didAdd node.
– Alok Subedi
Dec 24 '18 at 5:48












How does the creation of where I add my node affect that my video be played every time it comes to view? Even if it is on pause.
– impression7vx
Dec 24 '18 at 16:01





How does the creation of where I add my node affect that my video be played every time it comes to view? Even if it is on pause.
– impression7vx
Dec 24 '18 at 16:01













Not sure , just my guess, there must be some logical issue if it plays everytime imageAnchor is found.
– Alok Subedi
Dec 25 '18 at 4:41




Not sure , just my guess, there must be some logical issue if it plays everytime imageAnchor is found.
– Alok Subedi
Dec 25 '18 at 4:41












I added it for kicks and giggles
– impression7vx
Jan 1 at 20:11




I added it for kicks and giggles
– impression7vx
Jan 1 at 20:11












Where's the code for your ARWorldTrackingConfiguration used here? Would it be an option for you to stop the 'detection' once the video started playing?
– Mihai Erős
Jan 4 at 16:27




Where's the code for your ARWorldTrackingConfiguration used here? Would it be an option for you to stop the 'detection' once the video started playing?
– Mihai Erős
Jan 4 at 16:27












1 Answer
1






active

oldest

votes


















2





+400









Ok. So here is a fix. see renderer(_:updateAtTime:).



var player: AVPlayer!
var play = true

@objc func tap(_ recognizer: UITapGestureRecognizer)
if play
play = false
player.pause()
else
play = true
player.play()



func setVideo() -> SKScene
let size = CGSize(width: 500, height: 500)
let skScene = SKScene(size: size)

let videoURL = Bundle.main.url(forResource: "video.mp4", withExtension: nil)!
player = AVPlayer(url: videoURL)

skScene.scaleMode = .aspectFit

videoSpriteNode = SKVideoNode(avPlayer: player)
videoSpriteNode.position = CGPoint(x: size.width/2, y: size.height/2)
videoSpriteNode.size = size
videoSpriteNode.yScale = -1
skScene.addChild(videoSpriteNode)

player.play()

return skScene


func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)
if let image = anchor as? ARImageAnchor
print("found")

let planeGeometry = SCNPlane(width: image.referenceImage.physicalSize.width, height: image.referenceImage.physicalSize.height)
let plane = SCNNode(geometry: planeGeometry)
planeGeometry.materials.first?.diffuse.contents = setVideo()

plane.transform = SCNMatrix4MakeRotation(-.pi/2, 1, 0, 0)

node.addChildNode(plane)



func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval)
if !play
player.pause()




Use this idea in your code.






share|improve this answer






















  • What if the video is paused? That's my problem. I DON'T want the video to be on a loop. I want the ability to pause it. WITHOUT the system PLAYING my video everytime it comes into view
    – impression7vx
    2 days ago











  • If my problem was keeping the video playing, this would be easy. As it already does this. I want to pause my video and ONLY play it when I click on the node implementing a gesture type action.
    – impression7vx
    2 days ago










  • Will try it and let you know!
    – impression7vx
    2 days ago










  • You sly dawg. I used renderer(_:updateAtTime) for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding the if! play player.pause() . Great workaround, however, the natural behavior for Apple needs to be changed. Thanks for this, seriously. Have had this problem for a while
    – impression7vx
    2 days ago










Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53256602%2farkit-skvideonode-playing-on-render%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









2





+400









Ok. So here is a fix. see renderer(_:updateAtTime:).



var player: AVPlayer!
var play = true

@objc func tap(_ recognizer: UITapGestureRecognizer)
if play
play = false
player.pause()
else
play = true
player.play()



func setVideo() -> SKScene
let size = CGSize(width: 500, height: 500)
let skScene = SKScene(size: size)

let videoURL = Bundle.main.url(forResource: "video.mp4", withExtension: nil)!
player = AVPlayer(url: videoURL)

skScene.scaleMode = .aspectFit

videoSpriteNode = SKVideoNode(avPlayer: player)
videoSpriteNode.position = CGPoint(x: size.width/2, y: size.height/2)
videoSpriteNode.size = size
videoSpriteNode.yScale = -1
skScene.addChild(videoSpriteNode)

player.play()

return skScene


func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)
if let image = anchor as? ARImageAnchor
print("found")

let planeGeometry = SCNPlane(width: image.referenceImage.physicalSize.width, height: image.referenceImage.physicalSize.height)
let plane = SCNNode(geometry: planeGeometry)
planeGeometry.materials.first?.diffuse.contents = setVideo()

plane.transform = SCNMatrix4MakeRotation(-.pi/2, 1, 0, 0)

node.addChildNode(plane)



func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval)
if !play
player.pause()




Use this idea in your code.






share|improve this answer






















  • What if the video is paused? That's my problem. I DON'T want the video to be on a loop. I want the ability to pause it. WITHOUT the system PLAYING my video everytime it comes into view
    – impression7vx
    2 days ago











  • If my problem was keeping the video playing, this would be easy. As it already does this. I want to pause my video and ONLY play it when I click on the node implementing a gesture type action.
    – impression7vx
    2 days ago










  • Will try it and let you know!
    – impression7vx
    2 days ago










  • You sly dawg. I used renderer(_:updateAtTime) for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding the if! play player.pause() . Great workaround, however, the natural behavior for Apple needs to be changed. Thanks for this, seriously. Have had this problem for a while
    – impression7vx
    2 days ago















2





+400









Ok. So here is a fix. see renderer(_:updateAtTime:).



var player: AVPlayer!
var play = true

@objc func tap(_ recognizer: UITapGestureRecognizer)
if play
play = false
player.pause()
else
play = true
player.play()



func setVideo() -> SKScene
let size = CGSize(width: 500, height: 500)
let skScene = SKScene(size: size)

let videoURL = Bundle.main.url(forResource: "video.mp4", withExtension: nil)!
player = AVPlayer(url: videoURL)

skScene.scaleMode = .aspectFit

videoSpriteNode = SKVideoNode(avPlayer: player)
videoSpriteNode.position = CGPoint(x: size.width/2, y: size.height/2)
videoSpriteNode.size = size
videoSpriteNode.yScale = -1
skScene.addChild(videoSpriteNode)

player.play()

return skScene


func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)
if let image = anchor as? ARImageAnchor
print("found")

let planeGeometry = SCNPlane(width: image.referenceImage.physicalSize.width, height: image.referenceImage.physicalSize.height)
let plane = SCNNode(geometry: planeGeometry)
planeGeometry.materials.first?.diffuse.contents = setVideo()

plane.transform = SCNMatrix4MakeRotation(-.pi/2, 1, 0, 0)

node.addChildNode(plane)



func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval)
if !play
player.pause()




Use this idea in your code.






share|improve this answer






















  • What if the video is paused? That's my problem. I DON'T want the video to be on a loop. I want the ability to pause it. WITHOUT the system PLAYING my video everytime it comes into view
    – impression7vx
    2 days ago











  • If my problem was keeping the video playing, this would be easy. As it already does this. I want to pause my video and ONLY play it when I click on the node implementing a gesture type action.
    – impression7vx
    2 days ago










  • Will try it and let you know!
    – impression7vx
    2 days ago










  • You sly dawg. I used renderer(_:updateAtTime) for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding the if! play player.pause() . Great workaround, however, the natural behavior for Apple needs to be changed. Thanks for this, seriously. Have had this problem for a while
    – impression7vx
    2 days ago













2





+400







2





+400



2




+400




Ok. So here is a fix. see renderer(_:updateAtTime:).



var player: AVPlayer!
var play = true

@objc func tap(_ recognizer: UITapGestureRecognizer)
if play
play = false
player.pause()
else
play = true
player.play()



func setVideo() -> SKScene
let size = CGSize(width: 500, height: 500)
let skScene = SKScene(size: size)

let videoURL = Bundle.main.url(forResource: "video.mp4", withExtension: nil)!
player = AVPlayer(url: videoURL)

skScene.scaleMode = .aspectFit

videoSpriteNode = SKVideoNode(avPlayer: player)
videoSpriteNode.position = CGPoint(x: size.width/2, y: size.height/2)
videoSpriteNode.size = size
videoSpriteNode.yScale = -1
skScene.addChild(videoSpriteNode)

player.play()

return skScene


func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)
if let image = anchor as? ARImageAnchor
print("found")

let planeGeometry = SCNPlane(width: image.referenceImage.physicalSize.width, height: image.referenceImage.physicalSize.height)
let plane = SCNNode(geometry: planeGeometry)
planeGeometry.materials.first?.diffuse.contents = setVideo()

plane.transform = SCNMatrix4MakeRotation(-.pi/2, 1, 0, 0)

node.addChildNode(plane)



func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval)
if !play
player.pause()




Use this idea in your code.






share|improve this answer














Ok. So here is a fix. see renderer(_:updateAtTime:).



var player: AVPlayer!
var play = true

@objc func tap(_ recognizer: UITapGestureRecognizer)
if play
play = false
player.pause()
else
play = true
player.play()



func setVideo() -> SKScene
let size = CGSize(width: 500, height: 500)
let skScene = SKScene(size: size)

let videoURL = Bundle.main.url(forResource: "video.mp4", withExtension: nil)!
player = AVPlayer(url: videoURL)

skScene.scaleMode = .aspectFit

videoSpriteNode = SKVideoNode(avPlayer: player)
videoSpriteNode.position = CGPoint(x: size.width/2, y: size.height/2)
videoSpriteNode.size = size
videoSpriteNode.yScale = -1
skScene.addChild(videoSpriteNode)

player.play()

return skScene


func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)
if let image = anchor as? ARImageAnchor
print("found")

let planeGeometry = SCNPlane(width: image.referenceImage.physicalSize.width, height: image.referenceImage.physicalSize.height)
let plane = SCNNode(geometry: planeGeometry)
planeGeometry.materials.first?.diffuse.contents = setVideo()

plane.transform = SCNMatrix4MakeRotation(-.pi/2, 1, 0, 0)

node.addChildNode(plane)



func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval)
if !play
player.pause()




Use this idea in your code.







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 days ago

























answered 2 days ago









Alok SubediAlok Subedi

1,205517




1,205517











  • What if the video is paused? That's my problem. I DON'T want the video to be on a loop. I want the ability to pause it. WITHOUT the system PLAYING my video everytime it comes into view
    – impression7vx
    2 days ago











  • If my problem was keeping the video playing, this would be easy. As it already does this. I want to pause my video and ONLY play it when I click on the node implementing a gesture type action.
    – impression7vx
    2 days ago










  • Will try it and let you know!
    – impression7vx
    2 days ago










  • You sly dawg. I used renderer(_:updateAtTime) for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding the if! play player.pause() . Great workaround, however, the natural behavior for Apple needs to be changed. Thanks for this, seriously. Have had this problem for a while
    – impression7vx
    2 days ago
















  • What if the video is paused? That's my problem. I DON'T want the video to be on a loop. I want the ability to pause it. WITHOUT the system PLAYING my video everytime it comes into view
    – impression7vx
    2 days ago











  • If my problem was keeping the video playing, this would be easy. As it already does this. I want to pause my video and ONLY play it when I click on the node implementing a gesture type action.
    – impression7vx
    2 days ago










  • Will try it and let you know!
    – impression7vx
    2 days ago










  • You sly dawg. I used renderer(_:updateAtTime) for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding the if! play player.pause() . Great workaround, however, the natural behavior for Apple needs to be changed. Thanks for this, seriously. Have had this problem for a while
    – impression7vx
    2 days ago















What if the video is paused? That's my problem. I DON'T want the video to be on a loop. I want the ability to pause it. WITHOUT the system PLAYING my video everytime it comes into view
– impression7vx
2 days ago





What if the video is paused? That's my problem. I DON'T want the video to be on a loop. I want the ability to pause it. WITHOUT the system PLAYING my video everytime it comes into view
– impression7vx
2 days ago













If my problem was keeping the video playing, this would be easy. As it already does this. I want to pause my video and ONLY play it when I click on the node implementing a gesture type action.
– impression7vx
2 days ago




If my problem was keeping the video playing, this would be easy. As it already does this. I want to pause my video and ONLY play it when I click on the node implementing a gesture type action.
– impression7vx
2 days ago












Will try it and let you know!
– impression7vx
2 days ago




Will try it and let you know!
– impression7vx
2 days ago












You sly dawg. I used renderer(_:updateAtTime) for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding the if! play player.pause() . Great workaround, however, the natural behavior for Apple needs to be changed. Thanks for this, seriously. Have had this problem for a while
– impression7vx
2 days ago




You sly dawg. I used renderer(_:updateAtTime) for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding the if! play player.pause() . Great workaround, however, the natural behavior for Apple needs to be changed. Thanks for this, seriously. Have had this problem for a while
– impression7vx
2 days ago

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53256602%2farkit-skvideonode-playing-on-render%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Darth Vader #20

How to how show current date and time by default on contact form 7 in WordPress without taking input from user in datetimepicker

Ondo