ARKit SKVideoNode Playing on Render
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
|
show 6 more comments
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
can we seecreateVideoNode
plz. Normally we add video node as child of node indidAdd 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
|
show 6 more comments
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
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
swift avplayer arkit scnnode skvideonode
edited 2 days ago
impression7vx
asked Nov 12 '18 at 6:01
impression7vximpression7vx
2671836
2671836
can we seecreateVideoNode
plz. Normally we add video node as child of node indidAdd 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
|
show 6 more comments
can we seecreateVideoNode
plz. Normally we add video node as child of node indidAdd 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
|
show 6 more comments
1 Answer
1
active
oldest
votes
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.
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 usedrenderer(_:updateAtTime)
for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding theif! 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
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
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 usedrenderer(_:updateAtTime)
for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding theif! 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
add a comment |
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.
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 usedrenderer(_:updateAtTime)
for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding theif! 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
add a comment |
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.
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.
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 usedrenderer(_:updateAtTime)
for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding theif! 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
add a comment |
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 usedrenderer(_:updateAtTime)
for VARIOUS other activities in my app but never considered the possibility of this. This worked by adding theif! 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
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
can we see
createVideoNode
plz. Normally we add video node as child of node indidAdd 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