Skip to content

Commit

Permalink
fix i420 buffer rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
hiroshihorie committed Oct 12, 2023
1 parent caf1e4e commit 54f9489
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 3 deletions.
101 changes: 101 additions & 0 deletions Sources/LiveKit/Extensions/RTCI420Buffer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright 2023 LiveKit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import Foundation
import WebRTC

internal extension RTCI420Buffer {

func toPixelBuffer() -> CVPixelBuffer? {

// default options
let options = [
kCVPixelBufferCGImageCompatibilityKey as String: true,
kCVPixelBufferCGBitmapContextCompatibilityKey as String: true,
kCVPixelBufferIOSurfacePropertiesKey as String: [:] as [String: Any]
] as [String: Any]

var outputPixelBuffer: CVPixelBuffer?
let status = CVPixelBufferCreate(kCFAllocatorDefault,
Int(width),
Int(height),
kCVPixelFormatType_32BGRA,
options as CFDictionary,
&outputPixelBuffer)

guard status == kCVReturnSuccess, let outputPixelBuffer = outputPixelBuffer else {
return nil
}

CVPixelBufferLockBaseAddress(outputPixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
let pixelFormat = CVPixelBufferGetPixelFormatType(outputPixelBuffer)

if pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||
pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange {
// NV12
let dstY = CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 0)
let dstYStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 0)
let dstUV = CVPixelBufferGetBaseAddressOfPlane(outputPixelBuffer, 1)
let dstUVStride = CVPixelBufferGetBytesPerRowOfPlane(outputPixelBuffer, 1)

RTCYUVHelper.i420(toNV12: dataY,
srcStrideY: strideY,
srcU: dataU,
srcStrideU: strideU,
srcV: dataV,
srcStrideV: strideV,
dstY: dstY,
dstStrideY: Int32(dstYStride),
dstUV: dstUV,
dstStrideUV: Int32(dstUVStride),
width: width,
width: height)

} else {
let dst = CVPixelBufferGetBaseAddress(outputPixelBuffer)
let bytesPerRow = CVPixelBufferGetBytesPerRow(outputPixelBuffer)

if pixelFormat == kCVPixelFormatType_32BGRA {

RTCYUVHelper.i420(toARGB: dataY,
srcStrideY: strideY,
srcU: dataU,
srcStrideU: strideU,
srcV: dataV,
srcStrideV: strideV,
dstARGB: dst,
dstStrideARGB: Int32(bytesPerRow),
width: width,
height: height)
} else if pixelFormat == kCVPixelFormatType_32ARGB {

RTCYUVHelper.i420(toBGRA: dataY,
srcStrideY: strideY,
srcU: dataU,
srcStrideU: strideU,
srcV: dataV,
srcStrideV: strideV,
dstBGRA: dst,
dstStrideBGRA: Int32(bytesPerRow),
width: width,
height: height)
}
}

CVPixelBufferUnlockBaseAddress(outputPixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
return outputPixelBuffer
}
}
14 changes: 11 additions & 3 deletions Sources/LiveKit/Views/InternalSampleBufferVideoRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,20 @@ extension InternalSampleBufferVideoRenderer: RTCVideoRenderer {

guard let frame = frame else { return }

guard let rtcPixelBuffer = frame.buffer as? RTCCVPixelBuffer else {
log("frame.buffer is not a RTCCVPixelBuffer", .error)
var pixelBuffer: CVPixelBuffer?

if let rtcPixelBuffer = frame.buffer as? RTCCVPixelBuffer {
pixelBuffer = rtcPixelBuffer.pixelBuffer
} else if let rtcI420Buffer = frame.buffer as? RTCI420Buffer {
pixelBuffer = rtcI420Buffer.toPixelBuffer()
}

guard let pixelBuffer = pixelBuffer else {
log("pixelBuffer is nil", .error)
return
}

guard let sampleBuffer = CMSampleBuffer.from(rtcPixelBuffer.pixelBuffer) else {
guard let sampleBuffer = CMSampleBuffer.from(pixelBuffer) else {
log("Failed to convert CVPixelBuffer to CMSampleBuffer", .error)
return
}
Expand Down

0 comments on commit 54f9489

Please sign in to comment.