如何使用 AVFoundation 组合不同方向的视频剪辑

2024-05-02

我正在尝试使用 AVFoundation 将多个视频剪辑合并为一个。 我可以使用下面的代码使用 AVMutableComposition 创建单个视频

AVMutableComposition *composition = [AVMutableComposition composition];

AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

CMTime startTime = kCMTimeZero;

/*videoClipPaths is a array of paths of the video clips recorded*/

//for loop to combine clips into a single video
for (NSInteger i=0; i < [videoClipPaths count]; i++) {

    NSString *path = (NSString*)[videoClipPaths objectAtIndex:i];

    NSURL *url = [[NSURL alloc] initFileURLWithPath:path];

    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
    [url release];

    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    AVAssetTrack *audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];

    //set the orientation
    if(i == 0)
    {
        [compositionVideoTrack setPreferredTransform:videoTrack.preferredTransform];
    }

    ok = [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:videoTrack atTime:startTime error:nil];
    ok = [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:audioTrack atTime:startTime error:nil];

    startTime = CMTimeAdd(startTime, [asset duration]);
}

//export the combined video
NSString *combinedPath = /* path of the combined video*/;

NSURL *url = [[NSURL alloc] initFileURLWithPath: combinedPath];

AVAssetExportSession *exporter = [[[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPreset640x480] autorelease];

exporter.outputURL = url;
[url release];

exporter.outputFileType = [[exporter supportedFileTypes] objectAtIndex:0];

[exporter exportAsynchronouslyWithCompletionHandler:^(void){[self combineVideoFinished:exporter.outputURL status:exporter.status error:exporter.error];}];

如果所有视频剪辑都以相同方向(纵向或横向)录制,上面的代码可以正常工作。但是,如果剪辑中混合了多种方向,则最终视频的一部分将向右(或向左)旋转 90 度。

我想知道是否有一种方法可以在合成所有剪辑时将它们转换为相同的方向(例如第一个剪辑的方向)。根据我从 XCode 文档中读到的内容AVMutableVideoCompositionLayerInstruction似乎可以用来改造AVAsset,但我不确定如何创建多个不同的图层指令并将其应用到相应的剪辑,然后在合成中使用(AVMutableComposition*)

任何帮助,将不胜感激!


这就是我所做的。然后,我使用 AVAssetExportSession 创建实际文件。但我警告您,CGAffineTransforms 有时会延迟应用,因此您会在视频转换之前看到一两个原始内容。我不知道为什么会发生这种情况,不同的视频组合会产生预期的结果,但有时会失败。

AVMutableComposition *composition = [AVMutableComposition composition];    
AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; 
videoComposition.frameDuration = CMTimeMake(1,30); 
videoComposition.renderScale = 1.0;

AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack];

// Get only paths the user selected NSMutableArray *array = [NSMutableArray array]; for(NSString* string in videoPathArray){
if(![string isEqualToString:@""]){
    [array addObject:string];
} 

self.videoPathArray = array;

float time = 0;

for (int i = 0; i<self.videoPathArray.count; i++) {

    AVURLAsset *sourceAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[videoPathArray objectAtIndex:i]] options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey]];

    NSError *error = nil;

    BOOL ok = NO;
    AVAssetTrack *sourceVideoTrack = [[sourceAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

    CGSize temp = CGSizeApplyAffineTransform(sourceVideoTrack.naturalSize, sourceVideoTrack.preferredTransform);
    CGSize size = CGSizeMake(fabsf(temp.width), fabsf(temp.height));
    CGAffineTransform transform = sourceVideoTrack.preferredTransform;

    videoComposition.renderSize = sourceVideoTrack.naturalSize;
    if (size.width > size.height) {
        [layerInstruction setTransform:transform atTime:CMTimeMakeWithSeconds(time, 30)];
    } else {

        float s = size.width/size.height;

        CGAffineTransform new = CGAffineTransformConcat(transform, CGAffineTransformMakeScale(s,s));

        float x = (size.height - size.width*s)/2;

        CGAffineTransform newer = CGAffineTransformConcat(new, CGAffineTransformMakeTranslation(x, 0));

        [layerInstruction setTransform:newer atTime:CMTimeMakeWithSeconds(time, 30)];
    }

    ok = [compositionVideoTrack insertTimeRange:sourceVideoTrack.timeRange ofTrack:sourceVideoTrack atTime:[composition duration] error:&error];

    if (!ok) {
        // Deal with the error.
        NSLog(@"something went wrong");
    }

    NSLog(@"\n source asset duration is %f \n source vid track timerange is %f %f \n composition duration is %f \n composition vid track time range is %f %f",CMTimeGetSeconds([sourceAsset duration]), CMTimeGetSeconds(sourceVideoTrack.timeRange.start),CMTimeGetSeconds(sourceVideoTrack.timeRange.duration),CMTimeGetSeconds([composition duration]), CMTimeGetSeconds(compositionVideoTrack.timeRange.start),CMTimeGetSeconds(compositionVideoTrack.timeRange.duration));

    time += CMTimeGetSeconds(sourceVideoTrack.timeRange.duration);
}

instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
instruction.timeRange = compositionVideoTrack.timeRange; 
videoComposition.instructions = [NSArray arrayWithObject:instruction];

这就是我所做的。然后,我使用 AVAssetExportSession 创建实际文件。但我警告您,CGAffineTransforms 有时会延迟应用,因此您会在视频转换之前看到一两个原始内容。我不知道为什么会发生这种情况,不同的视频组合会产生预期的结果,但有时会失败。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 AVFoundation 组合不同方向的视频剪辑 的相关文章

随机推荐

  • 正则表达式 IPv6 验证和可选的方括号?

    大家好 这里的正则表达式新手 我正在尝试编写一个验证 IPv6 地址的正则表达式 我还没有添加端口部分 我想先让地址部分工作 这是我到目前为止所拥有的 0 9A Fa f 这使得左括号和右括号是可选的 但正如您所看到的 它们是独立可选的 有
  • 如何使用 hostPath 将单个文件映射到 kubernetes pod 中?

    我有一个自己的 nginx 配置 home ubuntu workspace web conf由脚本生成 我更喜欢把它放在下面 etc nginx conf d除了default conf 下面是nginx yaml apiVersion
  • JS专用鼠标按键

    我的鼠标侧面有两个按钮 其默认行为是 后退 和 前进 我想知道的是是否可以在 JavaScript 中检测这些鼠标按钮的点击 或者这些按钮是否是类似于键盘的 播放 音量调高 和 无线开 关 的 特殊 按钮纽扣 我不知道任何特定的鼠标事件 但
  • 修改变量后动态重新导入 Sass 部分

    我正在开发一个利用 Sass 预编译的 Twitter Bootstrap 的项目 每次覆盖变量时 我都必须重新导入 bootstrap sass文件到我的项目主样式表以使覆盖生效 您是否知道如何使此过程自动进行 以便每次修改变量时立即生效
  • AJAX 与 Facebook 身份验证

    我已经构建了一个完全基于 AJAX 的应用程序 它没有页面刷新并使用 AJAX 加载所有内容 现在我想以一种不会重定向用户进行页面刷新的方式嵌入 Facebook 身份验证 目前 Facebook 的工作方式如下 用户通过单击 Facebo
  • 无法使用 sysctl 更改每个进程的最大打开文件数

    我的实际极限是1024 ulimit a core file size blocks c 0 data seg size kbytes d unlimited scheduling priority e 0 file size blocks
  • 指定随机粒子起始颜色而不进行动画更改?

    有没有办法让粒子根据当前的 颜色渐变 产生随机的每个粒子颜色 粒子在其生命周期内不会改变颜色 它们只是在出生时从 颜色渐变 的某个地方被分配了一种颜色 并保持该颜色直到它们死亡 其结果将是出生时的粒子与从红色到蓝色的混合颜色的混合 在我的测
  • 在无头模式下独立运行 Unity,同时捕获屏幕截图

    我需要创建一个在无头模式下运行的统一项目 使用 batchmode 命令 但它必须捕获屏幕截图 例如每一秒并将它们写到一个文件中 我知道在无头模式下 您需要强制调用 Camera Render 才能渲染任何内容 在捕获第一个屏幕截图后 时间
  • Python Numpy TypeError:输入类型不支持 ufunc 'isfinite'

    这是我的代码 def topK dataMat sensitivity meanVals np mean dataMat axis 0 meanRemoved dataMat meanVals covMat np cov meanRemov
  • Apache CXF - WS 解决如何设置 From、ReplyTo、Headers

    我有一个问题 我们正在尝试使用 Apache CXF 实现 WS Addressing 我可以设置一些标头 例如 To 或 Action 但我找不到设置其他标头 例如 From ReplyTo 或 FaultTo 的方法 有人知道该怎么做吗
  • 在Python中解析空选项

    我有一个应用程序 允许您将事件数据发送到自定义脚本 您只需布置命令行参数并指定什么事件数据与什么参数相匹配 问题是这里没有真正的灵活性 您制定的每个选项都将被使用 但并非每个选项都必须有数据 因此 当应用程序构建要发送到脚本的字符串时 某些
  • height: calc(100%) 在 CSS 中无法正常工作

    我有一个 div 我想填充主体的整个高度减去设定的像素数 但我无法得到height calc 100 50px 上班 我想这样做的原因是我有一些元素具有基于一些不同标准的动态高度 例如标题的高度根据它可以包含的不同元素而变化 然后 内容 d
  • ANSI 转义码无法正确显示

    我有以下定义 define ANSI COLOR RED e 31m define ANSI COLOR GREEN e 32m define ANSI COLOR YELLOW e 33m define ANSI COLOR BLUE e
  • SQL Server - 评估期已过期错误

    昨天我的电脑上安装的 SQL Server 2014 试用期结束了 我决定使用 Express 版本并卸载 SQL Server 2014 并安装 Express 版本 但是当我打开SQL Server Management Studio时
  • 如何从网络客户端获取状态码?

    我正在使用WebClient类将一些数据发布到 Web 表单 我想获取表单提交的响应状态代码 到目前为止我已经找到了如果出现异常如何获取状态代码 Catch wex As WebException If TypeOf wex Respons
  • 如何使用 Angular2 数据表

    找不到任何使用教程angular2 data table图书馆在这里 https github com swimlane angular2 data table https github com swimlane angular2 data
  • 传递到 mvn exec:java 时保留参数间距等

    我有一个启动 Maven exec java 进程的 shell 脚本 exec mvn exec java Dexec mainClass Dexec args 现在可悲的是如果我跑步 myMagicShellScript arg1 ar
  • 比较字符串结尾的最佳方法是使用 RIGHT、LIKE 还是其他?

    我需要将字符串的结尾与存储过程中可能的结尾列表进行比较 会被叫很多 大概有10 15个候选结局 此时 仅使用代码的解决方案比创建专用于此的表更好 类似的东西 IF ENDSWITH var foo OR ENDSWITH var bar O
  • Android 支持 React Native 的 LayoutAnimation 吗?

    我没有看到文档中的任何内容 https facebook github io react native docs layoutanimation html指的是缺乏对Android的支持 我正在使用一个简单的预设动画 LayoutAnima
  • 如何使用 AVFoundation 组合不同方向的视频剪辑

    我正在尝试使用 AVFoundation 将多个视频剪辑合并为一个 我可以使用下面的代码使用 AVMutableComposition 创建单个视频 AVMutableComposition composition AVMutableCom