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

基于iOS Objective-C从MV-HEVC格式3D视频提取左右立体图像

iOS下用Objective-C提取MV-HEVC 3D视频的左右立体图像

核心逻辑

MV-HEVC格式的3D视频一般包含左右眼两个独立的视频轨道,或者单轨道内包含拼接的左右帧。针对多轨道场景,需要先定位到左右眼对应的视频轨道,再分别生成对应时间点的图像;单轨道拼接场景则需提取帧后手动裁剪拆分左右视图。

完整实现代码

多轨道场景处理

NSString *inputVideoPath = @"你的MV-HEVC视频本地路径";
NSURL *inputVideoURL = [NSURL fileURLWithPath:inputVideoPath];
AVURLAsset *inputAsset = [AVURLAsset URLAssetWithURL:inputVideoURL options:nil];

// 获取所有视频轨道
NSArray<AVAssetTrack *> *videoTracks = [inputAsset tracksWithMediaType:AVMediaTypeVideo];
if (videoTracks.count < 2) {
    NSLog(@"未检测到双视图轨道,切换至单轨道拼接处理逻辑");
    goto SingleTrackProcessing;
}

// 优先通过轨道元数据识别左右眼(示例:用extendedLanguageTag判断)
AVAssetTrack *leftEyeTrack = nil;
AVAssetTrack *rightEyeTrack = nil;
for (AVAssetTrack *track in videoTracks) {
    NSString *langTag = track.extendedLanguageTag;
    if ([langTag containsString:@"left"]) {
        leftEyeTrack = track;
    } else if ([langTag containsString:@"right"]) {
        rightEyeTrack = track;
    }
}
// 若元数据无标识,默认取前两个轨道作为左右眼
if (!leftEyeTrack || !rightEyeTrack) {
    leftEyeTrack = videoTracks[0];
    rightEyeTrack = videoTracks[1];
}

CGFloat frameRate = [leftEyeTrack nominalFrameRate];
NSInteger maxFrameCount = 100; // 根据需求设置最大提取帧数

for (NSInteger i = 1; i <= maxFrameCount; i++) {
    NSError *error = nil;
    CMTime time = CMTimeMake(i, (int32_t)frameRate);
    
    // 生成左眼图像
    AVAssetImageGenerator *leftGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:inputAsset];
    leftGenerator.requestedTimeToleranceBefore = kCMTimeZero;
    leftGenerator.requestedTimeToleranceAfter = kCMTimeZero;
    leftGenerator.tracks = @[leftEyeTrack];
    
    CGImageRef leftImageRef = [leftGenerator copyCGImageAtTime:time actualTime:NULL error:&error];
    if (error) {
        NSLog(@"左眼帧提取失败:%@", error.localizedDescription);
        continue;
    }
    UIImage *leftImage = [UIImage imageWithCGImage:leftImageRef];
    CGImageRelease(leftImageRef);
    
    // 生成右眼图像
    AVAssetImageGenerator *rightGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:inputAsset];
    rightGenerator.requestedTimeToleranceBefore = kCMTimeZero;
    rightGenerator.requestedTimeToleranceAfter = kCMTimeZero;
    rightGenerator.tracks = @[rightEyeTrack];
    
    CGImageRef rightImageRef = [rightGenerator copyCGImageAtTime:time actualTime:NULL error:&error];
    if (error) {
        NSLog(@"右眼帧提取失败:%@", error.localizedDescription);
        continue;
    }
    UIImage *rightImage = [UIImage imageWithCGImage:rightImageRef];
    CGImageRelease(rightImageRef);
    
    // 这里添加保存/处理左右图像的逻辑
    NSLog(@"已提取第%ld帧左右眼图像", (long)i);
}
return;

// 单轨道拼接场景处理
SingleTrackProcessing:
AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:inputAsset];
imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;
imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;

CGFloat singleTrackFrameRate = [[inputAsset tracksWithMediaType:AVMediaTypeVideo][0] nominalFrameRate];
for (NSInteger i = 1; i <= maxFrameCount; i++) {
    NSError *error = nil;
    CMTime time = CMTimeMake(i, (int32_t)singleTrackFrameRate);
    CGImageRef imageRef = [imageGenerator copyCGImageAtTime:time actualTime:NULL error:&error];
    if (error) {
        NSLog(@"帧提取失败:%@", error.localizedDescription);
        continue;
    }
    UIImage *fullImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    
    // 假设是左右拼接格式,拆分左右视图
    CGFloat width = fullImage.size.width;
    CGFloat height = fullImage.size.height;
    
    CGRect leftRect = CGRectMake(0, 0, width/2, height);
    CGImageRef leftCropRef = CGImageCreateWithImageInRect(fullImage.CGImage, leftRect);
    UIImage *leftImage = [UIImage imageWithCGImage:leftCropRef];
    CGImageRelease(leftCropRef);
    
    CGRect rightRect = CGRectMake(width/2, 0, width/2, height);
    CGImageRef rightCropRef = CGImageCreateWithImageInRect(fullImage.CGImage, rightRect);
    UIImage *rightImage = [UIImage imageWithCGImage:rightCropRef];
    CGImageRelease(rightCropRef);
    
    // 处理拆分后的左右图像
    NSLog(@"已拆分第%ld帧左右眼图像", (long)i);
}

关键注意事项

  • 轨道识别:优先通过轨道的extendedLanguageTag、metadata等元数据判断左右眼轨道,避免依赖默认顺序导致错误。
  • 帧精度:设置requestedTimeToleranceBefore和requestedTimeToleranceAfter为kCMTimeZero,确保提取精确时间点的帧。
  • 内存管理:手动调用CGImageRelease释放CGImageRef,避免内存泄漏。
  • 单轨道适配:若视频是上下堆叠格式,只需修改裁剪的CGRect参数即可(取上半部分为左眼,下半部分为右眼)。

内容的提问来源于stack exchange,提问作者pocketkai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 17:20:08