22

AVCaptureVideoDataOutputSampleBufferDelegate の captureOutput によって返される CMSampleBuffer のコピーを作成しようとしています。

CMSampleBuffers は事前に割り当てられた (15) バッファーのプールから取得されるため、それらへの参照をアタッチすると、それらを再収集できません。これにより、残りのすべてのフレームがドロップされます。

最適なパフォーマンスを維持するために、一部のサンプル バッファは、デバイス システムやその他のキャプチャ入力で再利用する必要がある場合があるメモリのプールを直接参照します。これは、メモリ ブロックが可能な限りコピーされない非圧縮デバイス ネイティブ キャプチャの場合によく見られます。複数のサンプル バッファがこのようなメモリ プールを長時間参照すると、入力は新しいサンプルをメモリにコピーできなくなり、それらのサンプルは削除されます。

提供された CMSampleBufferRef オブジェクトを長時間保持することでアプリケーションがサンプルを削除しているが、サンプル データに長期間アクセスする必要がある場合は、データを新しいバッファにコピーしてからサンプル バッファを解放することを検討してください (以前は保持されていた) ため、参照するメモリを再利用できます。

明らかに、CMSampleBuffer をコピーする必要がありますが、CMSampleBufferCreateCopy() は浅いコピーしか作成しません。したがって、CMSampleBufferCreate() を使用する必要があると結論付けました。12を埋めました!コンストラクターが必要とするパラメーターですが、私の CMSampleBuffers に blockBuffer が含まれていないという問題が発生しました (それが何であるかは完全にはわかりませんが、重要なようです)。

この質問は何度か聞かれましたが、答えられていません。

CMImageBuffer または CVImageBuffer のディープ コピーとSwift 2.0 での CMSampleBuffer のコピーの作成

考えられる答えの 1 つは、「最終的にこれを使用してディープ クローンを作成する方法を見つけました。すべてのコピー メソッドは、AVCaptureSession をロックするヒープ内のデータを再利用していました。そのため、データを NSMutableData オブジェクトに引き出してから、新しいサンプル バッファを作成しました。」SOのロブの功績。ただし、これを正しく行う方法がわかりません。

興味のある方は、これが の出力ですprint(sampleBuffer)。blockBuffer についての言及はありません。別名 CMSampleBufferGetDataBuffer は nil を返します。imageBuffer はありますが、CMSampleBufferCreateForImageBuffer を使用して「コピー」を作成しても、CMSampleBuffer が解放されないようです。


編集:この質問が投稿されて以来、私はメモリをコピーするさらに多くの方法を試してきました。

ユーザーKametrixomが試みたのと同じことをしました。これは、最初に CVPixelBuffer をコピーしてから、CMSampleBufferCreateForImageBuffer を使用して最終的なサンプル バッファーを作成するという、同じアイデアに対する私の試みです。ただし、これにより次の 2 つのエラーのいずれかが発生します。

  • memcpy 命令の EXC_BAD_ACCESS。別名、アプリケーションのメモリの外部にアクセスしようとすることによるセグメンテーション違反。
  • または、メモリは正常にコピーされますが、CMSampleBufferCreateReadyWithImageBuffer()結果コード -12743 で失敗します。これは、「指定されたメディアのフォーマットが指定されたフォーマットの説明と一致しないことを示します。たとえば、CMVideoFormatDescriptionMatchesImageBuffer に失敗する CVImageBuffer とペアになっているフォーマットの説明」です。

Kametrixom も私もCMSampleBufferGetFormatDescription(sampleBuffer)、ソース バッファーのフォーマット記述をコピーしようとしたことがわかります。したがって、指定されたメディアの形式が指定された形式の説明と一致しない理由がわかりません。

4

4 に答える 4

7

これは、最高評価の回答に対する Swift 3 ソリューションです。

extension CVPixelBuffer {
func copy() -> CVPixelBuffer {
    precondition(CFGetTypeID(self) == CVPixelBufferGetTypeID(), "copy() cannot be called on a non-CVPixelBuffer")

    var _copy : CVPixelBuffer?
    CVPixelBufferCreate(
        kCFAllocatorDefault,
        CVPixelBufferGetWidth(self),
        CVPixelBufferGetHeight(self),
        CVPixelBufferGetPixelFormatType(self),
        nil,
        &_copy)

    guard let copy = _copy else { fatalError() }

    CVPixelBufferLockBaseAddress(self, CVPixelBufferLockFlags.readOnly)
    CVPixelBufferLockBaseAddress(copy, CVPixelBufferLockFlags(rawValue: 0))


    let copyBaseAddress = CVPixelBufferGetBaseAddress(copy)
    let currBaseAddress = CVPixelBufferGetBaseAddress(self)

    memcpy(copyBaseAddress, currBaseAddress, CVPixelBufferGetDataSize(self))

    CVPixelBufferUnlockBaseAddress(copy, CVPixelBufferLockFlags(rawValue: 0))
    CVPixelBufferUnlockBaseAddress(self, CVPixelBufferLockFlags.readOnly)


    return copy
}
}
于 2017-05-11T20:57:44.463 に答える