Какой самый эффективный способ рендеринга потокового видео в SceneKit iOS? - PullRequest
1 голос
/ 11 апреля 2020

Я работаю над приложением SceneKit, которое показывает потоковое видео. В нем я создаю плоскость, прикрепляю к ней UIImage и сохраняю CALayer. Позже я получаю сжатый видеопоток, который распаковываю в CGImage. Затем я обновляю содержимое CALayer новым CGImage. Это все работает, однако частота кадров довольно низкая, и это не является проблемой потоковой передачи или распаковки.

Мой вопрос : есть ли более быстрый и эффективный способ сделать это? Я трансформировал SCNPlane, вращая и смещая его. Однако это должны быть только обновления матрицы и не должны изменять время рендеринга, так как вам нужно go через ту же матрицу для рендеринга SCNPlane в его исходных координатах.

Ответы [ 2 ]

0 голосов
/ 12 апреля 2020

Я думаю, что самый эффективный способ воспроизвести потоковое видео в iOS на SCNPlane - это использовать SKVideoNode .

И принять во внимание, что на iOS два наиболее эффективные форматы видео: H.264 и HEV C.

HEV C, также известный как H.265 (или MPEG-H Part 2), - это стандарт сжатия видео, разработанный как преемник широко используемого H.264 (или Advanced Video Coding, или MPEG-4 Part 10). Оба формата подходят для работы от батареи и оптимизированы для CPU-GPU.

Вот как вы можете воспроизводить видео в автономном режиме:

func loadTVSet(_ pose: SCNVector3) {

    let scene = SCNScene(named: "art.scnassets/tv.scn")!

    let teleNode: SCNNode? = scene.rootNode.childNode(withName: "tv_retro", 
                                                   recursively: true)

    teleNode?.position = pose

    let screenNode = teleNode?.childNode(withName: "plane", 
                                      recursively: true)

    let geo = screenNode?.geometry as! SCNPlane

    let videoNode = SKVideoNode(fileNamed: "art.scnassets/video.mp4")

    let spriteKitScene = SKScene(size: .init(width: geo.width * 640,
                                            height: geo.height * 360))

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

    videoNode.size = spriteKitScene.size

    spriteKitScene.addChild(videoNode)

    let screenMaterial = geo.materials.first(where: { $0.name == "video" } )

    screenMaterial?.diffuse.contents = spriteKitScene

    videoNode.play()

    self.sceneView.scene.rootNode.addChildNode(teleNode!)
}

А вот как вы можете настроить SKVideoNode для воспроизведения онлайн-видео:

var videoNode: SKVideoNode? = {

    guard let url = URL(string: "https://www.website.com/video.mp4")
    else { return nil }

    let asset = AVAsset(url: url)
    let playerItem = AVPlayerItem(asset: asset)
    let player = AVPlayer(playerItem: playerItem)

    return SKVideoNode(avPlayer: player)
}()
0 голосов
/ 11 апреля 2020

Преобразование в UIImage или CGImageRef является дорогостоящей операцией. Он создает представление процессора изображения в неоптимальном формате, а затем требует другого преобразования в представление GPU (MTLTexture). SceneKit поддерживает взятие AVPlayer экземпляров в качестве contents свойства материала. Это должен быть самый простой и эффективный способ отображения видео на плоскость.

Обновление: Если конвейер приложения построен на CVImageBufferRef (он же CVPixelBufferRef), то CVMetalTextureCache и CVMetalTextureCacheCreateTextureFromImage - это API-интерфейсы, которые вы должны использовать для эффективного создания MTLTexture экземпляров, которые должны быть установлены как contents свойств материала.

...