はじめに
CMSampleBuffer
をResizeしてサイズを小さく(大きく)したいことがあると思います。試していませんが、途中で CIImage
になっているので、回転、変形、加工などCIFilterで行う処理を適用できると思います。
環境
- Xcode11.1
- Swift 5.1
手順まとめ
- CMSampleTimingInfoを保存しておく
- CMSampleBufferをCIImageに変換する
- CIImageをResizeする
- ResizeしたCIImageをCVPixelBufferに変換する
- CVPixelBufferをCMSampleBufferに変換する
手順詳細
1.CMSampleTimingInfoを保存しておく
import ReplayKit final class Sample { let timingInfo: CMSampleTimingInfo init(sampleBuffer: CMSampleBuffer) { let presentationTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer) let duration = CMSampleBufferGetDuration(sampleBuffer) let decodeTimeStamp = CMSampleBufferGetDecodeTimeStamp(sampleBuffer) timingInfo = CMSampleTimingInfo(duration: duration, presentationTimeStamp: presentationTimeStamp, decodeTimeStamp: decodeTimeStamp) } }
2.CMSampleBufferをCIImageに変換する
private func generateCIImage(from sampleBuffer: CMSampleBuffer) -> CIImage? { guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return nil } let ciImage = CIImage(cvPixelBuffer: pixelBuffer) return ciImage }
3.CIImageをResizeする
private func resizeCIImage(from ciImage: CIImage, scale: CGFloat) -> CIImage? { guard let filter = CIFilter(name: "CILanczosScaleTransform") else { return nil } filter.setDefaults() filter.setValue(ciImage, forKey: kCIInputImageKey) filter.setValue(scale, forKey: kCIInputScaleKey) return filter.outputImage }
【追記】
こちらの処理は、CoreImage.CIFilterBuiltins - cockscomblog?の記事を参考にすると、もう少しスッキリ書けそうです。
4.ResizeしたCIImageをCVPixelBufferに変換する
private func generateCVPixelBuffer(from ciImage: CIImage) -> CVPixelBuffer? { let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary var pixelBuffer: CVPixelBuffer! let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(ciImage.extent.size.width), Int(ciImage.extent.size.height), kCVPixelFormatType_32BGRA, attrs, &pixelBuffer) guard status == kCVReturnSuccess else { print("CVPixelBufferCreateに失敗") return nil } let ciContext = CIContext() ciContext.render(ciImage, to: pixelBuffer, bounds: ciImage.extent, colorSpace: CGColorSpaceCreateDeviceRGB()) CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0)) return pixelBuffer }
5.CVPixelBufferをCMSampleBufferに変換する
この際に、保持しておいた CMSampleTimingInfo
を利用します。
private func generateCMSampleBuffer(from cvPixelBuffer: CVPixelBuffer) -> CMSampleBuffer? { var sampleBuffer: CMSampleBuffer? var timimgInfo: CMSampleTimingInfo = timingInfo var videoInfo: CMVideoFormatDescription! CMVideoFormatDescriptionCreateForImageBuffer(allocator: nil, imageBuffer: cvPixelBuffer, formatDescriptionOut: &videoInfo) CMSampleBufferCreateForImageBuffer(allocator: kCFAllocatorDefault, imageBuffer: cvPixelBuffer, dataReady: true, makeDataReadyCallback: nil, refcon: nil, formatDescription: videoInfo, sampleTiming: &timimgInfo, sampleBufferOut: &sampleBuffer) return sampleBuffer }
完成
これでResize処理をしたCMSampleBufferを生成することができます。