swift - 带有视频的 SCNPlane 可在模拟器上播放,但无法在设备上播放

标签 swift objective-c avfoundation scenekit

我有一个视频层想要渲染到 SCNPlane 上。它适用于模拟器,但不适用于设备。

这是一个视觉效果:

enter image description here

代码如下:

    //DISPLAY PLANE
    SCNPlane * displayPlane = [SCNPlane planeWithWidth:displayWidth height:displayHeight];
    displayPlane.cornerRadius = cornerRadius;
    
    SCNNode * displayNode = [SCNNode nodeWithGeometry:displayPlane];
    [scene.rootNode addChildNode:displayNode];
    
    //apply material
    SCNMaterial * displayMaterial = [SCNMaterial material];
    displayMaterial.diffuse.contents = [[UIColor greenColor] colorWithAlphaComponent:1.0f];
    [displayNode.geometry setMaterials:@[displayMaterial]];
    
    //move to front + position for rim
    displayNode.position = SCNVector3Make(0, rimTop - 0.08, /*0.2*/ 1);
 
    //create video item
    NSBundle * bundle = [NSBundle mainBundle];
    NSString * path = [bundle pathForResource:@"tv_preview" ofType:@"mp4"];
    NSURL * url = [NSURL fileURLWithPath:path];
 
    AVAsset * asset = [AVAsset assetWithURL:url];
    AVPlayerItem * item = [AVPlayerItem playerItemWithAsset:asset];
    queue = [AVQueuePlayer playerWithPlayerItem:item];
    looper = [AVPlayerLooper playerLooperWithPlayer:queue templateItem:item];
    queue.muted = true;
    
    layer = [AVPlayerLayer playerLayerWithPlayer:queue];
    layer.frame = CGRectMake(0, 0, w, h);
    layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    displayMaterial.diffuse.contents = layer;
    displayMaterial.doubleSided = true;
    [queue play];
    
    //[self.view.layer addSublayer:layer];

我可以确认实际的平面存在(如果未应用 avplayerlayer,则在上图中显示为绿色) - 上面的第一张图片。如果视频层直接添加到父 View 层(上面的底线),则它运行良好 - 上面的最终图像。我认为这可能是文件系统问题,但后来我想(?)视频不会在最终图像中播放。

编辑:设置队列(AVPlayer)直接在模拟器上工作,尽管很难看,但在设备上崩溃,并显示以下错误日志:

Error: Could not get pixel buffer (CVPixelBufferRef)
validateFunctionArguments:3797: failed assertion `Fragment Function(commonprofile_frag): incorrect type of texture (MTLTextureType2D) bound at texture binding at index 4 (expect MTLTextureTypeCube) for u_radianceTexture[0].'

最佳答案

我认为我的解决方案适合您 - 唯一的问题是这里需要进行一些小的更改:

#import <SceneKit/SceneKit.h>
#import <AVKit/AVKit.h>
#import <SpriteKit/SpriteKit.h>

@interface ViewController: UIViewController

@end

它适用于模拟器(在 Xcode 13.2.1 中)和设备(我在装有 iOS 15.3 的 iPhone X 上运行它)。我使用 640x360 H.265 视频。这里唯一的问题 - 视频循环时断断续续......

#import "ViewController.h"

@implementation ViewController

AVQueuePlayer *queue;
AVPlayerLooper *looper;
SKVideoNode *videoNode;

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    SCNView *sceneView = (SCNView *)self.view;
    sceneView.backgroundColor = [UIColor blackColor];
    sceneView.autoenablesDefaultLighting = YES;
    sceneView.allowsCameraControl = YES;
    sceneView.playing = YES;
    sceneView.loops = YES;
    
    SCNScene *scene = [SCNScene scene];
    sceneView.scene = scene;

    // Display
    SCNPlane *displayPlane = [SCNPlane planeWithWidth:1.6 height:0.9];
    SCNNode *displayNode = [SCNNode nodeWithGeometry:displayPlane];

    SCNMaterial *displayMaterial = [SCNMaterial material];
    displayMaterial.lightingModelName = SCNLightingModelConstant;
    displayMaterial.doubleSided = YES;
    
    // Video
    NSBundle *bundle = [NSBundle mainBundle];
    NSString *path = [bundle pathForResource:@"art.scnassets/hevc" 
                                                    ofType:@"mp4"];
    NSURL *url = [NSURL fileURLWithPath:path];

    AVAsset *asset = [AVAsset assetWithURL:url];
    AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:asset];
    queue = [AVQueuePlayer playerWithPlayerItem:item];
    queue.muted = NO;
    
    looper = [AVPlayerLooper playerLooperWithPlayer:queue templateItem:item];
    
    // SpriteKit video node
    videoNode = [SKVideoNode videoNodeWithAVPlayer:queue];
    videoNode.zRotation = -M_PI;
    videoNode.xScale = -1;
    
    SKScene *skScene = [SKScene sceneWithSize: CGSizeMake(
                                                displayPlane.width * 1000,
                                                displayPlane.height * 1000)];
    
    videoNode.position = CGPointMake(skScene.size.width / 2,
                                     skScene.size.height / 2);

    videoNode.size = skScene.size;
    [videoNode play];
    [skScene addChild:videoNode];
    
    displayMaterial.diffuse.contents = skScene;
    [displayNode.geometry setMaterials:@[displayMaterial]];
    
    [scene.rootNode addChildNode:displayNode];
}

@end

关于swift - 带有视频的 SCNPlane 可在模拟器上播放,但无法在设备上播放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69914593/

相关文章:

ios - 以编程方式在 AVCaptureVideoPreviewLayer 上添加 UIButton

arrays - Swift:获取二维数组中最小项的索引

objective-c - Xcode 4.2和ARC的iOS AVAudioPlayer双重声音播放问题

ios - 用 cornerRadius 圆化所有角是可行的,但是如果我只做底部的两个角,它会破坏我的 UITableView 上的滚动

ios - 在不停止设备声音/音乐的情况下录制视频

swift - 如何根据要求在 SceneKit 中添加动画

ios - 将我的 Obj-C 框架与 Swift 框架联系起来

ios - AudioUnitInitialize 导致 iOS 模拟器上出现 Allow Microphone access 提示

ios - 不同类中的委托(delegate)和数据源可能吗? - UITableView

ios - 在 iOS 中从头开始创建视频