Skip to content

Instantly share code, notes, and snippets.

Last active December 26, 2022 07:56
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
UIView to CMSampleBuffer (UIViewをCMSampleBufferに変換するExtension)
import UIKit
import CoreMedia
extension UIView {
func toCMSampleBuffer() -> CMSampleBuffer? {
let scale: CGFloat = UIScreen.main.scale
let size: CGSize = .init(width: bounds.width * scale, height: bounds.height * scale)
guard let pixelBuffer = makeCVPicelBuffer(scale: scale, size: size) else { return nil }
defer {
CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0))
guard let context = makeCGContext(scale: scale, size: size, pixelBuffer: pixelBuffer) else { return nil }
layer.render(in: context)
guard let formatDescription = makeCMFormatDescription(pixelBuffer: pixelBuffer) else { return nil }
do {
return try CMSampleBuffer(
imageBuffer: pixelBuffer,
formatDescription: formatDescription,
sampleTiming: getCMSampleTimingInfo()
} catch {
assertionFailure("Failed to create CMSampleBuffer: \(error)")
return nil
private func makeCVPicelBuffer(scale: CGFloat, size: CGSize) -> CVPixelBuffer? {
var pixelBuffer: CVPixelBuffer?
let createPixelBufferResult: CVReturn = CVPixelBufferCreate(
kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue!,
kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue!,
kCVPixelBufferIOSurfacePropertiesKey: [:] as CFDictionary,
] as CFDictionary,
if createPixelBufferResult != kCVReturnSuccess {
assertionFailure("Failed to create CVPixelBuffer: \(createPixelBufferResult)")
return nil
return pixelBuffer
private func makeCGContext(scale: CGFloat, size: CGSize, pixelBuffer: CVPixelBuffer) -> CGContext? {
guard let context: CGContext = .init(
data: CVPixelBufferGetBaseAddress(pixelBuffer),
width: Int(size.width),
height: Int(size.height),
bitsPerComponent: 8,
bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer),
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
) else { return nil }
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: scale, y: -scale)
return context
private func makeCMFormatDescription(pixelBuffer: CVPixelBuffer) -> CMFormatDescription? {
var formatDescription: CMFormatDescription?
let createImageBufferResult: CVReturn = CMVideoFormatDescriptionCreateForImageBuffer(
allocator: kCFAllocatorDefault,
imageBuffer: pixelBuffer,
formatDescriptionOut: &formatDescription
if createImageBufferResult != kCVReturnSuccess {
assertionFailure("Failed to create CMFormatDescription: \(createImageBufferResult)")
return nil
return formatDescription
private func getCMSampleTimingInfo() -> CMSampleTimingInfo {
let currentTime: CMTime = .init(
seconds: CACurrentMediaTime(),
preferredTimescale: 60
let timingInfo: CMSampleTimingInfo = .init(
duration: .init(seconds: 1, preferredTimescale: 60),
presentationTimeStamp: currentTime,
decodeTimeStamp: currentTime
return timingInfo
Copy link

fukemy commented Dec 26, 2022

hi, thanks for usefull gist. Did you tried to apply webrtc call with PIP mode?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment