CMSampleBuffer -> CVPixelBuffer
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
// nano timestamp가 필요한 경우
let scale:Float64 = 1_000_000_000
let time = Int64( CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) * scale)
CVPixelBuffer -> CMSampleBuffer
var sampleBuffer: CMSampleBuffer? = nil
let scale = CMTimeScale(1_000_000_000)
let time = CMTime(value: CMTimeValue( secondTimestamp * Double(scale)), timescale: scale)
var timimgInfo: CMSampleTimingInfo = CMSampleTimingInfo( duration: CMTime.invalid,
presentationTimeStamp: time,
decodeTimeStamp: CMTime.invalid)
var videoInfo: CMVideoFormatDescription? = nil
CMVideoFormatDescriptionCreateForImageBuffer(
allocator: nil,
imageBuffer: pixelBuffer,
formatDescriptionOut: &videoInfo)
CMSampleBufferCreateForImageBuffer(
allocator: kCFAllocatorDefault,
imageBuffer: pixelBuffer,
dateReady: true,
makeDateReadyCallback: nil,
refcon: nil,
formatDescription: videoInfo!,
sampleTiming: &timimgInfo,
sampleBufferOut: &sampleBuffer)
CVPixelBuffer 복사
원본과 대상의 픽셀포맷과 plane이 동일한 경우
CVPixelBufferLockBaseAddress(originBuffer, .ReadOnly)
CVPixelBufferLockBaseAddress(destBuffer, CVPixelBufferLockFlags(rawValue: 0))
for plane in 0 ..< CVPixelBufferGetPlaneCount(originBuffer) {
let dest = CVPixelBufferGetBaseAddressOfPlane(destBuffer, plane)
let source = CVPixelBufferGetBaseAddressOfPlane(originBuffer, plane)
let height = CVPixelBufferGetHeightOfPlane(originBuffer, plane)
let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(originBuffer, plane)
memcpy(dest, source, height * bytesPerRow)
}
CVPixelBufferUnlockBaseAddress(destBuffer, CVPixelBufferLockFlags(rawValue: 0))
CVPixelBufferUnlockBaseAddress(originBuffer, .ReadOnly)
CVPixelBuffer -> Data
CVPixelBufferLockBaseAddress( pixelBuffer, CVPixelBufferLockFlags(rawValue: 0) )
let width = CVPixelBufferGetWidth(pixelBuffer)
let format = CVPixelBufferGetPixelFormatType(pixelBuffer)
var data = Data()
for plane in 0..<CVPixelBufferGetPlaneCount(pixelBuffer) {
let address = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, plane)
let height = CVPixelBufferGetHeightOfPlane(pixelBuffer, plane)
let bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, plane)
let length = bytesPerRow * height
data.append(Data(bytes: address!, count: length))
}
CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
CMSampleBuffer -> Data
let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!)
let height = CVPixelBufferGetHeight(imageBuffer!)
let src_buff = CVPixelBufferGetBaseAddress(imageBuffer!)
let data = Data(bytes: src_buff, length: bytesPerRow * height)
CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
CVPixelBuffer -> CVMetalTexture
let colorFormat: MTLPixelFormat = .r8Unorm
let width = CVPixelBufferGetWidthOfPlane( pixelBuffer, planeIndex)
let height = CVPixelBufferGetHeightOfPlane( pixelBuffer, planeIndex)
var texture: CVMetalTexture?
let status = CVMetalTextureCacheCreateTextureFromImage(
nil,
textureCache,
pixelBuffer,
nil,
colorFormat,
width,
height,
planeIndex,
&texture)
if status != kCVReturnSuccess {
}
위 예처럼 텍스처 캐시를 사용하는 경우 캐시는 미리 생성
var textureCache: CVMetalTextureCache!
CVMetalTextureCacheCreate( nil, nil, self.device, nil, &textureCache)
CVMetalTexture -> MTLTexture
CVMetalTextureGetTexture( cvMetalTexture)
MTLTexture 데이터를 CVPixelBuffer로 복사
CVPixelBuffer 생성
var pixelBuffer: CVPixelBuffer?
CVPixelBufferCreate( kCFAllocatorDefault,
texture.width,
texture.height,
kCVPixelFormatType_32BGRA,
nil,
&self.pixelBuffer)
복사(렌더링 이후)
CVPixelBufferLockBaseAddress( pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
let pixelBufferBytes = CVPixelBufferGetBaseAddress( pixelBuffer )
let bytesPerRow = CVPixelBufferGetBytesPerRow( pixelBuffer )
let region = MTLRegionMake2D(0, 0, texture.width, texture.height)
texture.getBytes( pixelBufferBytes, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0)
CVPixelBufferUnlockBaseAddress( pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
CVPixelBuffer, vImage_Buffer를 사용한 크롭, 스케일링
픽셀포맷이 BGRA 인 경우만 고려
// 소스 픽셀 버퍼 크기
let srcWidth = CVPixelBufferGetWidth(srcPixelBuffer)
let srcHeight = CVPixelBufferGetHeight(srcPixelBuffer)
let srcPixelFormat = CVPixelBufferGetPixelFormatType(srcPixelBuffer)
if srcPixelFormat != kCVPixelFormatType_32BGRA {
assertionFailure("not supported pixel format")
}
// 타겟 픽셀 버퍼 크기
let dstWidth = 256
let dstHeight = 256
let offsetX = srcWidth / 2 - dstWidth / 2
let offsetY = srcHeight / 2 - dstHeight / 2
// 타겟 픽셀 버퍼 생성
let attributes: [String: Any] = [String(kCVPixelBufferMetalCompatibilityKey): true]
var dstPixelBuffer: CVPixelBuffer?
let result = CVPixelBufferCreate(nil,
dstWidth,
dstHeight,
srcPixelFormat,
attributes as CFDictionary,
&dstPixelBuffer)
if result != kCVReturnSuccess { return }
guard let dstPixelBuffer = dstPixelBuffer else { return }
// 소스 버퍼 lock
guard kCVReturnSuccess == CVPixelBufferLockBaseAddress(srcPixelBuffer, .readOnly) else { return }
defer { CVPixelBufferUnlockBaseAddress(srcPixelBuffer, CVPixelBufferLockFlags(rawValue: 0)) }
// 타겟 버퍼 lock
guard kCVReturnSuccess == CVPixelBufferLockBaseAddress(dstPixelBuffer, CVPixelBufferLockFlags(rawValue: 0)) else { return }
defer { CVPixelBufferUnlockBaseAddress(dstPixelBuffer, CVPixelBufferLockFlags(rawValue: 0)) }
//
guard let srcAddress = CVPixelBufferGetBaseAddress(srcPixelBuffer) else { return }
guard let dstAddress = CVPixelBufferGetBaseAddress(dstPixelBuffer) else { return }
let srcBytesPerRow = CVPixelBufferGetBytesPerRow(srcPixelBuffer)
let dstBytesPerRow = CVPixelBufferGetBytesPerRow(dstPixelBuffer)
// vImage_Buffer 생성
var srcBuffer = vImage_Buffer(data: srcAddress,
height: vImagePixelCount(srcHeight),
width: vImagePixelCount(srcWidth),
rowBytes: srcBytesPerRow)
var dstBuffer = vImage_Buffer(data: dstAddress,
height: vImagePixelCount(dstHeight),
width: vImagePixelCount(dstWidth),
rowBytes: dstBytesPerRow)
// 스케일 적용
if kvImageNoError != vImageScale_ARGB8888(&srcBuffer, &dstBuffer, nil, vImage_Flags(kvImageNoFlags)) {
return
}
'프로그래밍 > iOS,macOS' 카테고리의 다른 글
UITextView 자동 높이 (0) | 2021.06.03 |
---|---|
오디오유닛 레벨 계산 (0) | 2021.05.01 |
Image, PixelBuffer (0) | 2021.04.13 |
아이폰 로컬 화면 공유 : Broadcast Extension (0) | 2021.03.19 |
[Metal] 이미지렌더링~ 카메라 입력과 가우시안 블러~ (1) | 2021.02.13 |
[Metal] 이미지 렌더링~ 가우시안 블러~ Kernel 쉐이더 (0) | 2021.02.07 |
[Metal] 이미지 렌더링~ 가우시안 블러 (0) | 2021.02.07 |
[Metal] 이미지 렌더링~ 여러 텍스처 합치기 (0) | 2021.02.06 |
[Metal] 이미지 렌더링~ 텍스처에 렌더링 (0) | 2021.02.05 |
[Metal] 이미지 렌더링~ 텍스처 표시 (0) | 2021.02.03 |