gpt4 book ai didi

ios - AVFoundation:导出时正确地将视频适合 CALayer

转载 作者:行者123 更新时间:2023-12-01 15:59:00 27 4
gpt4 key购买 nike

问题:

我在获取使用 AVFoundation 创建的视频以在 VideoLayer 中显示时遇到问题,CALayer , 具有正确的尺寸。

示例:

这是视频的外观(在应用程序中向用户显示)

enter image description here

但是,这是导出时生成的视频:

enter image description here

详情

如您所见,它是一个方形视频,背景为绿色,视频适合指定帧。但是,生成的视频不适合 CALayer用于包含它(请参阅视频应拉伸(stretch)到的黑色空间?)。

有时视频确实填充了图层,但被拉伸(stretch)超出了边界(宽度太大或高度太大),并且通常无法保持视频的自然宽高比。

代码

CGRect displayedFrame = [self adjustedVideoBoundsFromVideo:gifVideo];//the cropped frame
CGRect renderFrame = [self renderSizeForGifVideo:gifVideo]; //the full rendersize
AVAsset * originalAsset = self.videoAsset;

AVAssetTrack * videoTrack = [[originalAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableComposition * mainComposition = [AVMutableComposition composition];

AVMutableCompositionTrack * compositionTrack = [mainComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

[compositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, originalAsset.duration) ofTrack:videoTrack atTime:kCMTimeZero error:nil];

CALayer * parentLayer = [CALayer layer];
CALayer * backgroundLayer = [CALayer layer];
CALayer * videoLayer = [CALayer layer];
parentLayer.frame = renderFrame;
backgroundLayer.frame = parentLayer.bounds;
backgroundLayer.backgroundColor = self.backgroundColor.CGColor;
videoLayer.frame = displayedFrame;
[parentLayer addSublayer:backgroundLayer];
[parentLayer addSublayer:videoLayer];


AVMutableVideoComposition * videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.frameDuration = CMTimeMake(1, 30);
videoComposition.renderSize = CGSizeMake(renderFrame.size.width, renderFrame.size.height);




videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool
videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];



AVMutableVideoCompositionInstruction * instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, mainComposition.duration);

AVMutableVideoCompositionLayerInstruction * layerInstruction = [AVMutableVideoCompositionLayerInstruction
videoCompositionLayerInstructionWithAssetTrack:videoTrack];


instruction.layerInstructions = @[layerInstruction];
videoComposition.instructions = @[instruction];



NSString* videoName = @"myNewGifVideo.mp4";

NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
{
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}

AVAssetExportSession * exporter = [[AVAssetExportSession alloc] initWithAsset:mainComposition presetName:AVAssetExportPresetHighestQuality];
exporter.videoComposition = videoComposition;
exporter.outputFileType = AVFileTypeMPEG4;
exporter.outputURL = exportUrl;

[exporter exportAsynchronouslyWithCompletionHandler:^
{
dispatch_async(dispatch_get_main_queue(), ^{
self.finalVideo = exportUrl;
[self.delegate shareManager:self didCreateVideo:self.finalVideo];
if (completionBlock){
completionBlock();
}
});
}];

我试过的:

我尝试调整 videoLayerframe , bounds , 和 contentGravity这没有任何用处。

我尝试添加 transformAVMutableVideoCompositionLayerInstruction将视频缩放到 displayRect 的大小(可以选择许多不同的视频,它们的宽度和高度是可变的。每个视频在生成的视频中显示不同,没有一个是正确的)变换有时会得到正确的一个维度(通常是宽度),但会弄乱另一个.如果我以稍微不同的方式裁剪/缩放视频,它永远不会始终正确地获得一个维度。

我试过更改 renderSizevideoComposition但这会破坏方形裁剪。

我似乎无法正确处理。如何让视频完美填满 videoLayerdisplayedFrame帧(最后说明:视频的 naturalSizedisplayedFrame 不同,这就是我尝试转换它的原因)?

最佳答案

当视频在您的 videoLayer 中呈现时,它有一个隐式变换 t应用(我们无权访问它,但这是渲染工具内部应用于视频的一些初始转换)。为了使视频在导出时完全填充该层,我们必须了解初始变换的来源。 t显示一个奇怪的行为:它依赖于 renderSize您的视频作品(在您的示例中,这将是一个正方形)。你可以看到,如果你设置 renderSize与其他任何内容相比,videoLayer 中呈现的视频的比例和纵横比也会发生变化 - 即使您没有更改 videoLayerframe一点也不。我看不出这种行为有什么意义(合成的帧和作为合成一部分的视频层的帧应该是完全独立的),所以我认为这是 AVVideoCompositionCoreAnimationTool 中的一个错误.
纠正 t 的不祥行为,将以下转换应用于您的 videoInstruction :

let bugFixTransform = CGAffineTransform(scaleX: renderSize.width/videoTrack.naturalSize.width,
y: renderSize.height/videoTrack.naturalSize.height)
videoLayerInstruction.setTransform(bugFixTransform, at: .zero)
然后视频将完全填满 videoLayer .
如果视频没有标准方向,则必须应用另外两个变换来固定方向和比例:
let orientationAspectTransform: CGAffineTransform
let sourceVideoIsRotated: Bool = videoTrack.preferredTransform.a == 0
if sourceVideoIsRotated {
orientationAspectTransform = CGAffineTransform(scaleX: videoTrack.naturalSize.width/videoTrack.naturalSize.height,
y: videoTrack.naturalSize.height/videoTrack.naturalSize.width)
} else {
orientationAspectTransform = .identity
}

let bugFixTransform = CGAffineTransform(scaleX: compositionSize.width/videoTrack.naturalSize.width,
y: compositionSize.height/videoTrack.naturalSize.height)
let transform =
videoTrack.preferredTransform
.concatenating(bugFixTransform)
.concatenating(orientationAspectTransform)
videoLayerInstruction.setTransform(transform, at: .zero)
更新:仅针对您使用 preferredTransform 的情况,请注意,它也已损坏(包括 iOS 14),并且在某些情况下可能会导致意外转换,请参阅 this question有关描述和解决方法。

关于ios - AVFoundation:导出时正确地将视频适合 CALayer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32211261/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com