2016-07-06 3 views
2

Ich erstelle ein SKScene mit SKVideoNode, dann auf eine Kugelgeometrie anwenden. HierFehler beim Erstellen von IOSurface-Bild (Textur) mit GVRSDK

ist der Schlüsselcode:

// Create a SKScene to play video 
NSString* filePath = [[NSBundle mainBundle] pathForResource:@"2222" ofType:@"mp4"]; 
NSURL* sourceMovieURL = [NSURL fileURLWithPath:filePath]; 
AVPlayer* player = [AVPlayer playerWithURL:sourceMovieURL]; 
SKVideoNode* videoNode = [SKVideoNode videoNodeWithAVPlayer:player]; 

//CGSize size = CGSizeMake(512, 512); 
CGSize size = [UIScreen mainScreen].bounds.size; 
videoNode.size = size; 
videoNode.position = CGPointMake(size.width/2.0, size.height/2.0); 
SKScene* spriteScene = [SKScene sceneWithSize:size]; 
[spriteScene addChild:videoNode]; 


// create a material with SKScene 
SCNMaterial* material = [SCNMaterial material]; 
material.doubleSided = true; 
material.diffuse.contents = spriteScene; 


[sphereNode.geometry replaceMaterialAtIndex:0 withMaterial:material]; 

[videoNode play]; 

[_scnScene.rootNode addChildNode:sphereNode]; 

// create SCNRenderer to render the scene 
_renderer = [SCNRenderer rendererWithContext:cardboardView.context options:nil]; 
_renderer.scene = _scnScene; 
_renderer.pointOfView = _scnCameraNode; 

In der drawEye Funktion:

- (void)cardboardView:(GVRCardboardView *)cardboardView drawEye:(GVREye)eye withHeadTransform:(GVRHeadTransform *)headTransform 
{ 
//CGRect viewport = [headTransform viewportForEye:eye]; 

// Get the head matrix. 
const GLKMatrix4 head_from_start_matrix = [headTransform headPoseInStartSpace]; 

// Get this eye's matrices. 
GLKMatrix4 projection_matrix = [headTransform projectionMatrixForEye:eye near:_scnCamera.zNear far:_scnCamera.zFar]; 


GLKMatrix4 eye_from_head_matrix = [headTransform eyeFromHeadMatrix:eye]; 

// Compute the model view projection matrix. 
GLKMatrix4 view_projection_matrix = GLKMatrix4Multiply(
                 projection_matrix, GLKMatrix4Multiply(eye_from_head_matrix, head_from_start_matrix)); 
// Set the projection matrix to camera 
[_scnCamera setProjectionTransform:SCNMatrix4FromGLKMatrix4(view_projection_matrix)]; 


// Render the scene 
[_renderer renderAtTime:0]; 

} 

wenn der Code ausgeführt, es mit

[_renderer renderAtTime:0] 

brechen wird und der Ausgang ist:

Failed to create IOSurface image (texture) 
Assertion failed: (result), function create_texture_from_IOSurface, file /BuildRoot/Library/Caches/com.apple.xbs/Sources/Jet/Jet-2.6.1/Jet/jet_context_OpenGL.mm, line 570. 

Wenn ich den SKVideoNode aus dem SKScene entferne, ist alles in Ordnung.

Irgendwelche Hilfe? Vielen Dank.

+0

Wir haben das gleiche Problem haben, außer es nicht auf allen unseren Geräten auftritt ... oder möglicherweise Versionen von iOS. Welche Geräte und Version (en) von iOS, xcode und Mac laufen Sie? – caseyh

+0

Gerät ist iPhone 6s, ios9.3.2, Mac mini (Ende 2014) OS X EI Caption Version 10.11.5 mit xcode 7.3.1 – guiyuan

+0

So ist unsere Arbeitshypothese, dass auf der 5s und höher mit IOS 9 + gibt es eine Änderung oder Fehler durch das Betriebssystem eingeführt. Wir denken, es ist möglich, dass es mit der Präferenz von iOS auf diesen Geräten zusammenhängt, Metal über OpenGL zu verwenden, aber das ist jetzt mehr Spekulation. Wir werden mehr veröffentlichen, wenn wir mehr finden. – caseyh

Antwort

1

Update: Das funktioniert OK für Videos niedriger Qualität, aber qualitativ hochwertige, die nicht so viele Bytes kopieren. Ich habe es noch nicht ausprobiert, aber mein nächster Ansatz ist die Verwendung einer OpenGL-Textur mit einem CVPixelBuffer für bessere Leistung.

-

Ich weiß nicht, ob Sie immer noch nach einer Lösung, aber ich habe etwas Glück habe einen Video-Bereich arbeitet mit SceneKit/GVR auf iOS 9.3 auf einem 6s und iOS 8 sim bekommen. Ich kann jedoch nicht für alle Plattformen bürgen!

Ich habe SpriteKit komplett gelöscht und stattdessen einen CALayer verwendet, dessen Inhalt ich als CGImage von einem CVPixelBuffer gesetzt habe.

Der Videocode: (zunächst basierend auf this OpenGL 360 video tutorial)

init(url: NSURL) 
 
{ 
 
    self.videoURL = url 
 
    super.init() 
 
    self.configureVideoPlayback() 
 
} 
 

 
private override init() 
 
{ 
 
    self.videoURL = nil 
 
    super.init() 
 
} 
 

 
deinit 
 
{ 
 
    self.playerItem.removeOutput(self.videoOutput) 
 
} 
 

 
private func configureVideoPlayback() 
 
{ 
 
    let pixelBufferAttributes = [ 
 
     kCVPixelBufferPixelFormatTypeKey as String : NSNumber(unsignedInt: kCVPixelFormatType_32ARGB), 
 
     kCVPixelBufferCGImageCompatibilityKey as String: true, 
 
     kCVPixelBufferOpenGLESCompatibilityKey as String: true 
 
    ] 
 
    self.videoOutput = AVPlayerItemVideoOutput(pixelBufferAttributes: pixelBufferAttributes) 
 
    
 
    self.playerItem = AVPlayerItem(URL: self.videoURL) 
 
    self.playerItem.addOutput(self.videoOutput) 
 
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(VideoReader.playerItemDidPlayToEndTime(_:)), name: AVPlayerItemDidPlayToEndTimeNotification, object: self.playerItem) 
 

 
    self.player = AVPlayer(playerItem: self.playerItem) 
 
    self.player.play() 
 
} 
 

 
func currentPixelBuffer() - > CVPixelBuffer ? { 
 
    guard self.playerItem ? .status == .ReadyToPlay 
 
    else { 
 
     return nil 
 
    } 
 
    
 
    let currentTime = self.playerItem.currentTime() 
 
    return self.videoOutput.copyPixelBufferForItemTime(currentTime, itemTimeForDisplay: nil) 
 
} 
 

 
func playerItemDidPlayToEndTime(notification: NSNotification) 
 
{ 
 
    self.player.seekToTime(kCMTimeZero) 
 
    self.player.play() 
 
}

Szene:

func setupScene() { 
 
    self.scene = SCNScene() 
 

 
    self.imageLayer = CALayer() 
 
    self.imageLayer.frame = CGRectMake(0, 0, 2048, 2048) //Doesn't work if not power of 2 or incremenets inbetween - need to investigate 
 

 
    let material = SCNMaterial() 
 
    material.doubleSided = true 
 
    material.diffuse.contents = self.imageLayer 
 

 
    let geometry = SCNSphere(radius: 10) 
 

 
    let sphere = SCNNode(geometry: geometry) 
 
    sphere.geometry ? .replaceMaterialAtIndex(0, withMaterial: material) 
 
    sphere.position = SCNVector3(0, 0, 0) 
 
    sphere.scale.y = 1 
 
    sphere.scale.z = -1 
 

 
    self.scene!.rootNode.addChildNode(sphere) 
 
}

Pappe Draw Rahmen Prep:

func cardboardView(cardboardView: GVRCardboardView!, prepareDrawFrame headTransform: GVRHeadTransform!) { 
 
    
 
    // .. boilerplate code 
 

 
    if let pixelBuffer = self.videoReader.currentPixelBuffer() { 
 
    CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
 

 
    let width = CVPixelBufferGetWidth(pixelBuffer) 
 
    let height = CVPixelBufferGetHeight(pixelBuffer) 
 
    let pixels = CVPixelBufferGetBaseAddress(pixelBuffer); 
 

 
    let pixelWrapper = CGDataProviderCreateWithData(nil, pixels, CVPixelBufferGetDataSize(pixelBuffer), nil); 
 

 
    // Get a color-space ref... can't this be done only once? 
 
    let colorSpaceRef = CGColorSpaceCreateDeviceRGB(); 
 

 
    // Get a CGImage from the data (the CGImage is used in the drawLayer: delegate method above) 
 

 
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.NoneSkipFirst.rawValue) 
 
    if let currentCGImage = CGImageCreate(width, 
 
     height, 
 
     8, 
 
     32, 
 
     4 * width, 
 
     colorSpaceRef, [.ByteOrder32Big, bitmapInfo], 
 
     pixelWrapper, 
 
     nil, 
 
     false, 
 
     .RenderingIntentDefault) { 
 
     self.imageLayer.contents = currentCGImage 
 
    } 
 

 
    // Clean up 
 
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 
 

 
    } 
 
}

Meine erste Implementierung von GVR und SceneKit auf dieser basiert boilerplate

Die Framerate scheint immer noch hoch genug zu sein, für Ich - es ist noch nicht optimiert, aber ich werde diese Antwort aktualisieren, wenn ich es tue.

Hinweis:

  • Die CALayer Grenzen brauchen Potenz von 2 zu sein scheint - oder Schritte dazwischen, es kein Video nicht zeigen, wenn ich für Werte zwischen wie 1960 gehe
  • Es läuft wirklich langsam in Simulator aber bei 60fps auf dem Gerät für mich
+0

Danke für deine Antwort! Es hat funktioniert! Aber es gibt ein neues Problem, es bricht nach Serval Sekunden mit // Render die Szene [_renderer renderAtTime: 0]; Dann verwende ich die VRBoilerplate wie oben erwähnt, es ist auch an der gleichen Stelle brechen. wenn glGetError() == GLenum (GL_NO_ERROR) { eyeRenderer.renderAtTime (0); } – guiyuan

+0

Das ist nicht gut. Hast du es mit einem anderen Video versucht? Welches Telefon benutzt du? Ich habe den ganzen Videocode nicht hochgeladen, da ich es nicht für relevant hielt, aber ich werde ihn jetzt aktualisieren, so dass er 'loadValuesAsynchronousForKeys' auf dem AVURLAsset verwendet - der Video-Reader-Teil basiert auf diesem Tutorial https: // www .nomtek.com/video-360-in-opengl-ios-part-4-video-reader/ –

+0

Eigentlich könnte es einfacher sein, nur einen AVPlayer anstatt AVURLAsset zu verwenden. Angenommen, das Problem kommt von der Videowiedergabe, wenn der GL-Code von Anfang an reibungslos funktioniert. Ich habe den Code in meiner Antwort vereinfacht, hoffentlich hilft es. Falls nicht, versuchen Sie, Fehlerbenachrichtigungs-Listener zum AVPlayerItem hinzuzufügen –

0

denke ich, der Grund, das SDK gesetzt die SCNView ist ‚s APImachen. Setzen Sie einfach die API auf Standard (Metal), um dieses Problem zu beheben.

Überprüfen Sie, ob es etwas ist Code wie:

[[SVNView alloc] initWithFrame:CGRect() options:@{SCNPreferredRenderingAPIKey: [NSNumber numberWithInt:SCNRenderingAPIOpenGLES2]}] 

Ändern Sie diese an:

[[SVNView alloc] initWithFrame:CGRect() options:nil] or [[SVNView alloc] initWithFrame:CGRect()] 
Verwandte Themen