Support i420

This commit is contained in:
Isaac
2024-01-06 01:50:58 +04:00
parent 91fa88a4e8
commit 49cbbc9436

View File

@@ -815,14 +815,53 @@ private final class AdaptedCallVideoSource: VideoSource {
} }
} }
final class PixelBufferPool {
let width: Int
let height: Int
let pool: CVPixelBufferPool
init?(width: Int, height: Int) {
self.width = width
self.height = height
let bufferOptions: [String: Any] = [
kCVPixelBufferPoolMinimumBufferCountKey as String: 4 as NSNumber
]
let pixelBufferOptions: [String: Any] = [
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange as NSNumber,
kCVPixelBufferWidthKey as String: width as NSNumber,
kCVPixelBufferHeightKey as String: height as NSNumber,
kCVPixelBufferIOSurfacePropertiesKey as String: [:] as NSDictionary
]
var pool: CVPixelBufferPool?
CVPixelBufferPoolCreate(nil, bufferOptions as CFDictionary, pixelBufferOptions as CFDictionary, &pool)
guard let pool else {
return nil
}
self.pool = pool
}
}
final class PixelBufferPoolState {
var pool: PixelBufferPool?
}
private static let queue = Queue(name: "AdaptedCallVideoSource") private static let queue = Queue(name: "AdaptedCallVideoSource")
private var onUpdatedListeners = Bag<() -> Void>() private var onUpdatedListeners = Bag<() -> Void>()
private(set) var currentOutput: Output? private(set) var currentOutput: Output?
private var textureCache: CVMetalTextureCache? private var textureCache: CVMetalTextureCache?
private var pixelBufferPoolState: QueueLocalObject<PixelBufferPoolState>
private var videoFrameDisposable: Disposable? private var videoFrameDisposable: Disposable?
init(videoStreamSignal: Signal<OngoingGroupCallContext.VideoFrameData, NoError>) { init(videoStreamSignal: Signal<OngoingGroupCallContext.VideoFrameData, NoError>) {
let pixelBufferPoolState = QueueLocalObject(queue: AdaptedCallVideoSource.queue, generate: {
return PixelBufferPoolState()
})
self.pixelBufferPoolState = pixelBufferPoolState
CVMetalTextureCacheCreate(nil, nil, MetalEngine.shared.device, nil, &self.textureCache) CVMetalTextureCacheCreate(nil, nil, MetalEngine.shared.device, nil, &self.textureCache)
self.videoFrameDisposable = (videoStreamSignal self.videoFrameDisposable = (videoStreamSignal
@@ -917,47 +956,62 @@ private final class AdaptedCallVideoSource: VideoSource {
sourceId: sourceId sourceId: sourceId
) )
case let .i420(i420Buffer): case let .i420(i420Buffer):
guard let pixelBufferPoolState = pixelBufferPoolState.unsafeGet() else {
return
}
let width = i420Buffer.width let width = i420Buffer.width
let height = i420Buffer.height let height = i420Buffer.height
/*output = Output( let pool: PixelBufferPool?
resolution: CGSize(width: CGFloat(width), height: CGFloat(height)), if let current = pixelBufferPoolState.pool, current.width == width, current.height == height {
textureLayout: .triPlanar(Output.TriPlanarTextureLayout( pool = current
y: yTexture, } else {
uv: uvTexture pool = PixelBufferPool(width: width, height: height)
)), pixelBufferPoolState.pool = pool
dataBuffer: Output.NativeDataBuffer(pixelBuffer: nativeBuffer.pixelBuffer), }
rotationAngle: rotationAngle, guard let pool else {
followsDeviceOrientation: followsDeviceOrientation,
mirrorDirection: mirrorDirection,
sourceId: sourceId
)*/
let _ = width
let _ = height
return return
}
/*var cvMetalTextureY: CVMetalTexture? let auxAttributes: [String: Any] = [kCVPixelBufferPoolAllocationThresholdKey as String: 5 as NSNumber]
var status = CVMetalTextureCacheCreateTextureFromImage(nil, textureCache, nativeBuffer.pixelBuffer, nil, .r8Unorm, width, height, 0, &cvMetalTextureY) var pixelBuffer: CVPixelBuffer?
let result = CVPixelBufferPoolCreatePixelBufferWithAuxAttributes(kCFAllocatorDefault, pool.pool, auxAttributes as CFDictionary, &pixelBuffer)
if result == kCVReturnWouldExceedAllocationThreshold {
print("kCVReturnWouldExceedAllocationThreshold, dropping frame")
return
}
guard let pixelBuffer else {
return
}
if !copyI420BufferToNV12Buffer(buffer: i420Buffer, pixelBuffer: pixelBuffer) {
return
}
var cvMetalTextureY: CVMetalTexture?
var status = CVMetalTextureCacheCreateTextureFromImage(nil, textureCache, pixelBuffer, nil, .r8Unorm, width, height, 0, &cvMetalTextureY)
guard status == kCVReturnSuccess, let yTexture = CVMetalTextureGetTexture(cvMetalTextureY!) else { guard status == kCVReturnSuccess, let yTexture = CVMetalTextureGetTexture(cvMetalTextureY!) else {
return return
} }
var cvMetalTextureUV: CVMetalTexture? var cvMetalTextureUV: CVMetalTexture?
status = CVMetalTextureCacheCreateTextureFromImage(nil, textureCache, nativeBuffer.pixelBuffer, nil, .rg8Unorm, width / 2, height / 2, 1, &cvMetalTextureUV) status = CVMetalTextureCacheCreateTextureFromImage(nil, textureCache, pixelBuffer, nil, .rg8Unorm, width / 2, height / 2, 1, &cvMetalTextureUV)
guard status == kCVReturnSuccess, let uvTexture = CVMetalTextureGetTexture(cvMetalTextureUV!) else { guard status == kCVReturnSuccess, let uvTexture = CVMetalTextureGetTexture(cvMetalTextureUV!) else {
return return
} }
output = Output( output = Output(
resolution: CGSize(width: CGFloat(yTexture.width), height: CGFloat(yTexture.height)), resolution: CGSize(width: CGFloat(yTexture.width), height: CGFloat(yTexture.height)),
textureLayout: .biPlanar(Output.BiPlanarTextureLayout(
y: yTexture, y: yTexture,
uv: uvTexture, uv: uvTexture
dataBuffer: Output.NativeDataBuffer(pixelBuffer: nativeBuffer.pixelBuffer), )),
dataBuffer: Output.NativeDataBuffer(pixelBuffer: pixelBuffer),
rotationAngle: rotationAngle, rotationAngle: rotationAngle,
followsDeviceOrientation: followsDeviceOrientation, followsDeviceOrientation: followsDeviceOrientation,
mirrorDirection: mirrorDirection, mirrorDirection: mirrorDirection,
sourceId: sourceId sourceId: sourceId
)*/ )
default: default:
return return
} }