0

ソースビデオがあり、ソースビデオの各フレームの領域を取得して、そこから新しいビデオを生成したいと考えています。たとえば、解像度Ax B、コンテンツ サイズXx Y、出力解像度Cxのビデオがある場合、元のビデオの各フレームの最初のxピクセルをコンテンツとする解像度xDのビデオを作成します。CDXY

これを実現するためにAVAssetReader、ソース ビデオの読み取りには を使用しAVAssetWriter、新しいビデオの書き込みには を使用しています。ソース ビデオの領域Xxだけを抽出するために、アセット リーダーの出力としてオブジェクトを使用しています。セットアップ コードは次のようなものです。YAVAssetReaderVideoCompositionOutput

let output = AVAssetReaderVideoCompositionOutput(...)
output.videoComposition = AVMutableVideoComposition(
    asset: asset, 
    videoTrack: videoTrack, 
    contentRect: contentRect, 
    renderSize: renderSize
)

次に、ビデオ コンテンツをトリミングするためのロジックは、次のカスタム初期化子で発生します。

extension AVMutableVideoComposition {
    convenience init(asset: AVAsset, videoTrack: AVAssetTrack, contentRect: CGRect, renderSize: CGSize) {
        // Compute transform for rendering the video content at `contentRect` with a size equal to `renderSize`.
        let trackFrame = CGRect(origin: .zero, size: videoTrack.naturalSize)
        let transformedFrame = trackFrame.applying(videoTrack.preferredTransform)
        let moveToOriginTransform = CGAffineTransform(translationX: -transformedFrame.minX, y: -transformedFrame.minY)
        let moveToContentRectTransform = CGAffineTransform(translationX: -contentRect.minX, y: -contentRect.minY)
        let scaleTransform = CGAffineTransform(scaleX: renderSize.width / contentRect.width, y: renderSize.height / contentRect.height)
        let transform = videoTrack.preferredTransform.concatenating(moveToOriginTransform).concatenating(moveToContentRectTransform).concatenating(scaleTransform)

        let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
        layerInstruction.setTransform(transform, at: .zero)

        let instruction = AVMutableVideoCompositionInstruction()
        instruction.timeRange = CMTimeRange(start: .zero, duration: asset.duration)
        instruction.layerInstructions = [layerInstruction]

        self.init(propertiesOf: asset)
        instructions = [instruction]
        self.renderSize = renderSize
    }
}

このコードは、コンテンツのサイズなど、場合によっては正常に機能します(origin = (x = 0, y = 0), size = (width = 1416, height = 1920))。ただし、幅を 1417 に変更すると機能せず、次のエラー メッセージが表示されます。

Error Domain=AVFoundationErrorDomain Code=-11858 "Source frame unsupported format" UserInfo={NSUnderlyingError=0x283e689c0 {Error Domain=NSOSStatusErrorDomain Code=-12502 "(null)"}, NSLocalizedFailureReason=ビデオを合成できませんでした., NSDebugDescription=ソース フレームサポートされていない形式、NSLocalizedDescription=操作停止}

これは、エラーが発生したテスト ビデオを含むサンプル プロジェクトへのリンクです。幅1416、1421、1422、1423、1429で機能し、1416と1429の間の他のすべての幅値で失敗するため、これがランダムに見える場合があります。ここで何が問題で、どうすれば問題を解決できますか?

なぜこのアプローチを使用するのですか?

を使用するAVAssetReaderVideoCompositionOutput代わりに を使用してAVAssetReaderTrackOutput手動でクロッピングを行う理由は、前者を使用するとアプリのメモリ フットプリントを削減できるためです。サイズ。これは、同時に複数のビデオを処理している場合に関係します。

4

0 に答える 0