2017-01-11 20 views
2

私は簡単なことが必要です:ビデオを再生し、回転させながら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されている:あなたが見ることができるように

enter image description here

enter image description here

は、回転は、結果としてフレームの範囲に成功していますまた正しい。

このビデオはプレーヤーで再生しようとすると問題が発生します。ここで私が得るものです:すべてのフレームがスケーリングとシフトダウンしているよう

enter image description here

そう思えます。緑の領域は空のフレーム情報です。枠を無限大にするために範囲を固定すると、緑の代わりに境界ピクセルが表示されます。

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は回転情報をビデオに入れて修正します)。そのため、ビデオをズームしてシフトすることは、回転前に「アスペクトフィル」と古い解像度情報の組み合わせのように見えます。ちなみに、ポートレートビデオフレームは、アスペクト比が異なるプレーヤーエリアを塗りつぶすスケーリングのために部分的に表示されますが、これは予想される動作です。

私はこのことについてあなたの考えを知ってもらい、もし私が必要とするものを達成するためのよりよい方法を知っていれば、それは知っていると素晴らしいでしょう。

答えて

2

UPDATE:再生中に「変更」する簡単な方法AVPlayerItemビデオのサイズがあるように出てくる - (AVMutableVideoCompositionクラスを使用して行うことができます)映像組成物のrenderSizeプロパティを設定します。

以下の私のOLD ANSWER:


は、デバッグ、多くの後、私は問題を理解し、解決策を見つけました。私の最初の推測では、AVPlayerはまだビデオが元のサイズであるとみなしますが正しいと思います。その下の画像では何が起こっているか説明します

enter image description here

は解決策として、私はAVAssetまたはAVPlayerItem内のビデオサイズを変更する方法を見つけることができませんでした。だから私はちょうどAVPlayerが期待していたサイズとスケールに合うようにビデオを操作しました。そして、正しいアスペクトレシオのプレイヤーでプレイし、プレーヤーのエリアを塗りつぶしてフラッグをつけてください。ここでは、グラフィカルな説明は次のとおりです。

enter image description here

そして、ここでは問題に言及したapplyingCIFiltersWithHandlerブロックに挿入する必要がある追加のコード行く:

... after Step 3 in the question codes above 

// make the frame the same aspect ratio as the original input frame 
// by adding empty spaces at the top and the bottom of the extent rectangle 
CGFloat newHeight = originalExtent.size.height * originalExtent.size.height/extent.size.height; 
CGFloat inset = (extent.size.height - newHeight)/2; 
extent = CGRectInset(extent, 0, inset); 
sourceImage = [sourceImage imageByCroppingToRect:extent]; 

// scale down to the original frame size 
CGFloat scale = originalExtent.size.height/newHeight; 
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scale, scale); 
[transformFilter setValue:sourceImage forKey: kCIInputImageKey]; 
[transformFilter setValue: [NSValue valueWithCGAffineTransform: scaleTransform] forKey: kCIInputTransformKey]; 
sourceImage = transformFilter.outputImage; 

// translate the frame to make it's origin start at (0, 0) 
CGAffineTransform translation = CGAffineTransformMakeTranslation(0, -inset * scale); 
[transformFilter setValue:sourceImage forKey: kCIInputImageKey]; 
[transformFilter setValue: [NSValue valueWithCGAffineTransform: translation] forKey: kCIInputTransformKey]; 
sourceImage = transformFilter.outputImage; 
関連する問題