5

簡単なことが必要です。ビデオを回転させて適用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));

次に、ビデオ構成を適用する必要があります。もともと、私はAVVideoComposition2 つの命令で作成することを考えていました.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;

デバッグ中に作成したスクリーンショットは、画像が正常に回転し、フィルターが適用されたことを示しています (この例では、画像を変更しない ID フィルターでした)。上記のコメントでマークされたポイントで撮影されたスクリーンショット 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 はビデオに回転情報を入れて修正します)。そのため、ビデオのズームとシフトは、回転前の「アスペクト フィル」と古い解像度情報の組み合わせのように見えます。ちなみに、縦長のビデオ フレームは、アスペクト比が異なるプレーヤー領域を埋めるためにスケーリングされるため、部分的に表示されますが、これは想定された動作です。

これについてのあなたの考えを教えてください。私が必要とすることを達成するためのより良い方法を知っているなら、それを知っていただければ幸いです.

4

1 に答える 1