SCNPlane挂载AVPlayerLayer播放视频模拟器正常但真机失效问题求助
问题原因
- AVPlayerLayer无法直接作为SCNMaterial的contents在真机运行:模拟器采用CPU软渲染逻辑对CALayer作为纹理输入做了兼容,但真机运行SceneKit依赖Metal硬渲染管线,不支持直接读取CALayer的内容作为材质纹理,这是第一种写法真机无法显示视频的核心原因。
- 直接传入AVQueuePlayer崩溃的原因有两个:一是iOS 15之前的系统版本对AVPlayer直接作为SceneKit材质输入的适配存在缺陷;二是当前使用的SCNMaterial开启了PBR相关的光照配置,渲染管线将2D的视频纹理误判为环境立方体贴图读取,触发了类型不匹配的断言错误,同时视频的像素格式不符合Metal纹理采样要求,才会出现
Could not get pixel buffer (CVPixelBufferRef)报错。
修复方案
- 优先采用兼容性最高的SpriteKit中间层方案:放弃直接使用AVPlayerLayer或AVPlayer作为材质输入,用SKVideoNode包装AVPlayer,再赋值给SCNMaterial,该方案兼容iOS 11及以上所有系统版本,模拟器和真机表现一致:
// 原有创建AVQueuePlayer、AVPlayerLooper的代码保持不变 queue.muted = true; looper = [AVPlayerLooper playerLooperWithPlayer:queue templateItem:item]; // 替换原有AVPlayerLayer相关代码 SKVideoNode *videoNode = [SKVideoNode videoNodeWithAVPlayer:queue]; videoNode.size = CGSizeMake(w, h); // 调整坐标系避免视频上下翻转 videoNode.yScale = -1; videoNode.position = CGPointMake(w/2, h/2); SKScene *skScene = [SKScene sceneWithSize:CGSizeMake(w, h)]; [skScene addChild:videoNode]; // 赋值给SCNPlane材质 displayMaterial.diffuse.contents = skScene; displayMaterial.lightingModelName = SCNLightingModelConstant; // 关闭PBR光照避免纹理类型冲突 displayMaterial.doubleSided = YES; [queue play]; [videoNode play];
- 若使用上述方案仍有异常,检查两个配置项:
- 确认你的mp4文件采用H.264编码,不要使用HEVC等其他编码格式,避免Metal采样像素失败
- 若视频尺寸特殊,可临时调整为1024*512这类2的幂次尺寸测试,排除纹理尺寸兼容问题
- 若坚持使用AVPlayer直接作为材质输入,需将App的最低支持系统版本提升到iOS 15,同时给AVPlayerItem添加像素buffer输出配置:
NSDictionary *bufferAttr = @{(id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA)}; AVPlayerItemVideoOutput *output = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:bufferAttr]; [item addOutput:output];
内容的提问来源于stack exchange,提问作者Johnny Rockex
相关产品推荐
相关产品推荐

