You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 01:30:24