2016-07-06 2 views
2

Создаю SKScene с SKVideoNode, затем применим к геометрии сферы.Не удалось создать изображение IOSurface (текстуру) с помощью GVRSDK

Вот ключевой код:

// 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; 

В функции drawEye:

- (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]; 

} 

При выполнении кода, он сломается с

[_renderer renderAtTime:0] 

и выход:

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. 

Когда я удаляю SKVideoNode из SKScene, все в порядке.

Любая помощь? Благодарю.

+0

У нас есть один и тот же вопрос, за исключением того, что не происходит на всех наших устройств ... или возможно, версии iOS. Какие устройства и версии iOS, xcode и mac вы используете? – caseyh

+0

Устройство iphone 6s, ios9.3.2, Mac mini (конец 2014 г.) OS X EI Caption версия 10.11.5 с xcode 7.3.1 – guiyuan

+0

Итак, наша рабочая гипотеза заключается в том, что на 5 и более с ios 9+ есть изменения или ошибки, внесенные ОС. Мы считаем, что возможно, это может быть связано с предпочтением iOS на тех устройствах, которые используют металл поверх OpenGL, но это скорее спекуляция прямо сейчас. Мы отправим больше, если найдем больше. – caseyh

ответ

1

Обновление: Это работает нормально для видео низкого качества, но высококачественные не выполняют большое количество копий. Я еще не пробовал, но мой следующий подход использует текстуру OpenGL с CVPixelBuffer для лучшей производительности.

-

Я не знаю, если вы все еще ищете решение, но у меня было немного удачи, получая видео сферы работы с SceneKit/GVR на прошивке 9.3 на течение 6 секунд и IOS 8 сим. Однако я не могу ручаться за все платформы!

Я полностью потерял SpriteKit и переехал вместо этого для использования CALayer, содержимое которого я установил как CGImage из CVPixelBuffer.

видео Код: (первоначально основанный на 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() 
 
}

Сцена:

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) 
 
}

Картон ленточная 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); 
 

 
    } 
 
}

Моя первоначальная реализация GVR и SceneKit основано на этом boilerplate

Частота кадров до сих пор, кажется, достаточно высока, я - он еще не оптимизирован, но я буду обновлять этот ответ, когда буду.

Примечание:

  • Граница CALayer должна быть степенью 2, кажется, - или приращение между ними, он не показывает видео, когда я иду для значений между как 1960.
  • Он работает очень медленно в симуляторе, но при 60fps на устройстве для меня
+0

Спасибо за ваш ответ! Это сработало! Но есть новая проблема, она прерывается после секунд серваля с // Оказывать сцену [_renderer renderAtTime: 0]; Затем я использую VRBoilerplate, как упоминалось выше, он также разбивается на одну и ту же точку. if glGetError() == GLenum (GL_NO_ERROR) { eyeRenderer.renderAtTime (0); } – guiyuan

+0

Это не хорошо. Вы пробовали это с другим видео? Какой телефон вы используете? Я не поместил полный видеокод, так как не думал, что это актуально, но я сейчас его обновлю, поэтому он использует «loadValuesAsynchronouslyForKeys» на AVURLAsset - часть видеопроигрывателя основана на этом учебнике https: // www .nomtek.com/video-360-in-opengl-ios-part-4-video-reader/ –

+0

На самом деле может быть проще просто использовать AVPlayer, а не AVURLAsset. Предполагая, что проблема исходит от воспроизведения видео, если код GL запускается гладко для начала. Я упростил код в своем ответе, надеюсь, это помогает. Если не попробовать добавить слушателей уведомлений об ошибках в AVPlayerItem –

0

Я думаю, что причина заключается в SDK установить SCNView «s делают API для OpenGLES. Просто установите API по умолчанию (Metal), чтобы устранить эту проблему.

Проверьте, есть ли какой-то код, как:

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

Изменить это:

[[SVNView alloc] initWithFrame:CGRect() options:nil] or [[SVNView alloc] initWithFrame:CGRect()] 
Смежные вопросы