私は簡単なことが必要です:ビデオを再生し、回転させながらCIFilter
を適用します。AVPlayerはビデオの合成結果を正しく再生しません
はまず、私はプレイヤーのアイテムを作成:
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つの命令で作成しようと考えていました.1つは回転のためにAVVideoCompositionLayerInstruction
になり、もう1つは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されている:あなたが見ることができるように
は、回転は、結果としてフレームの範囲に成功していますまた正しい。
このビデオはプレーヤーで再生しようとすると問題が発生します。ここで私が得るものです:すべてのフレームがスケーリングとシフトダウンしているよう
そう思えます。緑の領域は空のフレーム情報です。枠を無限大にするために範囲を固定すると、緑の代わりに境界ピクセルが表示されます。
が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]
プレイヤーは次のとおりです。私は、なぜ最初のコードスニペットでは、私はサイズや変換をログに記録された上記のことだ、プレイヤーはまだAVPlayerItem
から回転する前に、いくつかの古いサイズ情報を取る気持ちを持って、ログがありますこのように設定:これは唯一のiPhone風景にカメラを使用してアプリ自体によって記録された動画に起こる [6S]オリエンテーションやデバイスのストレージに保存された:
layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
layer.needsDisplayOnBoundsChange = YES;
最も重要なことに注意してください。前にusly。アプリはポートレートモードで記録するビデオは完全に素晴らしいです(ちなみに、ポートレートのビデオはランドスケープビデオのように正確に同じサイズと変換ログ!奇妙なことに... iphoneは回転情報をビデオに入れて修正します)。そのため、ビデオをズームしてシフトすることは、回転前に「アスペクトフィル」と古い解像度情報の組み合わせのように見えます。ちなみに、ポートレートビデオフレームは、アスペクト比が異なるプレーヤーエリアを塗りつぶすスケーリングのために部分的に表示されますが、これは予想される動作です。
私はこのことについてあなたの考えを知ってもらい、もし私が必要とするものを達成するためのよりよい方法を知っていれば、それは知っていると素晴らしいでしょう。