自定义customVideoCompositorClass后视频黑屏,sourcePixelBuffer始终为nil
问题分析与修复方案
核心问题
你的CustomVideoCompositor中requiredSourceTrackIDsForFrame:方法返回nil,导致AVFoundation无法确定需要为你提供哪个轨道的视频帧数据,这直接造成sourcePixelBuffer始终为nil,最终画面黑屏。另外还有两个次要问题:
- 获取轨道ID时错误地将
NSNumber强制转为int,正确类型应为CMTrackID requiredPixelBufferAttributesForRenderContext返回nil不符合API要求,需返回空数组或正确的属性指令
修复后的代码
1. 修正CustomVideoCompositor实现
#import <AVFoundation/AVFoundation.h> #import "AAPLViewController.h" @implementation CustomVideoCompositor - (nullable id<AVVideoCompositionInstruction>)requiredSourceTrackIDsForFrame:(CMTime)frameTime { // 创建指令,指定需要所有源轨道的帧数据 AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.requiredSourceTrackIDs = [self.renderContext.sourceTrackIDs copy]; return instruction; } - (NSArray<AVVideoCompositionInstruction *> *)requiredPixelBufferAttributesForRenderContext { // 返回空数组而非nil,符合API规范 return @[]; } - (void)startVideoCompositionRequest:(AVAsynchronousVideoCompositionRequest *)request { // 正确转换轨道ID类型为CMTrackID NSArray *trackIDs = request.sourceTrackIDs; if (trackIDs.count == 0) { [request finishWithError:[NSError errorWithDomain:@"CustomCompositor" code:-1 userInfo:@{NSLocalizedDescriptionKey:@"No source tracks available"}]]; return; } CMTrackID trackID = [(NSNumber *)trackIDs[0] integerValue]; CVPixelBufferRef sourcePixelBuffer = [request sourceFrameByTrackID:trackID]; if (!sourcePixelBuffer) { [request finishWithError:[NSError errorWithDomain:@"CustomCompositor" code:-2 userInfo:@{NSLocalizedDescriptionKey:@"Failed to get source pixel buffer"}]]; return; } [request finishWithComposedVideoFrame:sourcePixelBuffer]; } - (NSDictionary *)sourcePixelBufferAttributes { return @{ (id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA) }; } - (void)renderContextChanged:(AVVideoCompositionRenderContext *)newRenderContext { // 可在此处理渲染上下文变化,比如更新输出尺寸等 } @end
2. 优化ViewController中的视频合成配置
- (void)viewDidLoad { [super viewDidLoad]; NSURL *url = [[NSBundle mainBundle] URLForResource:@"1" withExtension:@"mov"]; AVAsset *asset = [AVAsset assetWithURL:url]; AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoCompositionWithPropertiesOfAsset:asset]; videoComposition.customVideoCompositorClass = [CustomVideoCompositor class]; // 显式设置合成指令,确保轨道ID正确映射 AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] firstObject]; if (videoTrack) { AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration); AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; instruction.layerInstructions = @[layerInstruction]; videoComposition.instructions = @[instruction]; } AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset]; playerItem.videoComposition = videoComposition; AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem]; AVPlayerViewController *controller = [[AVPlayerViewController alloc] init]; self.playerViewController = controller; CGSize videoSize = [[[asset tracksWithMediaType:AVMediaTypeVideo] firstObject] naturalSize]; [self addChildViewController:controller]; [self.view addSubview:controller.view]; controller.view.frame = CGRectMake(-70, 270, videoSize.width * SCALE, videoSize.height * SCALE); controller.view.transform = CGAffineTransformMakeRotation(M_PI_2); controller.player = player; controller.showsPlaybackControls = YES; [player play]; }
关键说明
requiredSourceTrackIDsForFrame:必须返回有效的AVVideoCompositionInstruction,明确告诉系统需要哪些轨道的帧数据,否则AVFoundation不会提供任何像素缓冲区- 轨道ID的类型是
CMTrackID(本质是NSInteger),需从NSNumber正确转换,不能直接强制转为int - 显式设置
videoComposition.instructions可以确保视频轨道被正确识别,避免自动生成的指令与自定义 compositor 不兼容
内容的提问来源于stack exchange,提问作者demonguy
相关产品推荐
相关产品推荐

