我需要一个简单的东西:一边旋转一边播放视频并应用CIFilter
它。
首先,我创建播放器项目:
AVPlayerItem *item = [AVPlayerItem playerItemWithURL:videoURL];
// DEBUG LOGGING
AVAssetTrack *track = [[item.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
NSLog(@"Natural size is: %@", NSStringFromCGSize(track.naturalSize));
NSLog(@"Preffered track transform is: %@", NSStringFromCGAffineTransform(track.preferredTransform));
NSLog(@"Preffered asset transform is: %@", NSStringFromCGAffineTransform(item.asset.preferredTransform));
然后我需要应用视频合成。最初,我想创建一个AVVideoComposition
带有 2 条指令的指令 - 一条AVVideoCompositionLayerInstruction
用于轮换,另一条用于CIFilter
应用。但是,我收到一个异常,说“期望视频合成仅包含 AVCoreImageFilterVideoCompositionInstruction”,这意味着 Apple 不允许组合这 2 个指令。结果,我在过滤下结合了两者,这里是代码:
AVAsset *asset = playerItem.asset;
CGAffineTransform rotation = [self transformForItem:playerItem];
AVVideoComposition *composition = [AVVideoComposition videoCompositionWithAsset:asset applyingCIFiltersWithHandler:^(AVAsynchronousCIImageFilteringRequest * _Nonnull request) {
// Step 1: get the input frame image (screenshot 1)
CIImage *sourceImage = request.sourceImage;
// Step 2: rotate the frame
CIFilter *transformFilter = [CIFilter filterWithName:@"CIAffineTransform"];
[transformFilter setValue:sourceImage forKey: kCIInputImageKey];
[transformFilter setValue: [NSValue valueWithCGAffineTransform: rotation] forKey: kCIInputTransformKey];
sourceImage = transformFilter.outputImage;
CGRect extent = sourceImage.extent;
CGAffineTransform translation = CGAffineTransformMakeTranslation(-extent.origin.x, -extent.origin.y);
[transformFilter setValue:sourceImage forKey: kCIInputImageKey];
[transformFilter setValue: [NSValue valueWithCGAffineTransform: translation] forKey: kCIInputTransformKey];
sourceImage = transformFilter.outputImage;
// Step 3: apply the custom filter chosen by the user
extent = sourceImage.extent;
sourceImage = [sourceImage imageByClampingToExtent];
[filter setValue:sourceImage forKey:kCIInputImageKey];
sourceImage = filter.outputImage;
sourceImage = [sourceImage imageByCroppingToRect:extent];
// Step 4: finish processing the frame (screenshot 2)
[request finishWithImage:sourceImage context:nil];
}];
playerItem.videoComposition = composition;
我在调试期间制作的屏幕截图显示图像已成功旋转并应用了过滤器(在此示例中,它是一个不改变图像的身份过滤器)。这是在上面评论中标记的点拍摄的屏幕截图 1 和屏幕截图 2:
如您所见,旋转成功,生成的帧的范围也是正确的。
当我尝试在播放器中播放此视频时,问题就开始了。这是我得到的:
所以似乎所有的帧都按比例缩小并向下移动。绿色区域是空帧信息,当我夹紧到范围以使帧无限大小时,它显示边框像素而不是绿色。我有一种感觉,玩家在旋转之前仍然会从AVPlayerItem
.
Natural size is: {1920, 1080}
Preffered track transform is: [0, 1, -1, 0, 1080, 0]
Preffered asset transform is: [1, 0, 0, 1, 0, 0]
播放器设置如下:
layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
layer.needsDisplayOnBoundsChange = YES;
请注意最重要的事情:这只发生在应用程序本身使用相机以横向iPhone [6s] 方向录制并之前保存在设备存储中的视频。该应用程序以纵向模式录制的视频完全没有问题(顺便说一句,纵向视频的大小和转换日志就像横向视频一样!奇怪......也许iphone将旋转信息放入视频并修复它)。因此,缩放和移动视频似乎是“方面填充”和旋转前旧分辨率信息的组合。顺便说一句,纵向视频帧的显示部分是因为缩放以填充具有不同纵横比的播放器区域,但这是预期的行为。
让我知道您对此的想法,如果您知道如何实现我需要的更好的方法,那么很高兴知道。