Created
May 5, 2017 14:53
-
-
Save omarojo/14e513130f92237f812c215928aaefba to your computer and use it in GitHub Desktop.
LF Custom Static Buffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import lf | |
import UIKit | |
import XCGLogger | |
import AVFoundation | |
let sampleRate:Double = 44_100 | |
final class LiveViewController: UIViewController { | |
//..... | |
// | |
var PTS = kCMTimeZero | |
var timer : Timer? = nil | |
var testSamplePixelBuffer : CVPixelBuffer? = nil | |
func startPushingCustomContent(){ | |
createOncePixelBuffer() | |
//start a timer to run at desired framerate. | |
self.timer = Timer.scheduledTimer(timeInterval: 1.0 / Double(30), //30 fps | |
target: self, | |
selector: #selector(pushCustomBuffer), | |
userInfo: nil, | |
repeats: true); | |
} | |
func createOncePixelBuffer(){ | |
let myimage = UIImage(named: "myimage")! | |
self.testSamplePixelBuffer = pixelBufferFromImage(image: myimage); //creates a pixelbufffer from an image | |
} | |
func stopPushingCustomContent(){ | |
PTS = kCMTimeZero | |
self.timer?.invalidate(); | |
} | |
//MARK: Custom Content Stream | |
func pushCustomBuffer (){ | |
if let imageBuffer = self.testSamplePixelBuffer { | |
var timingInfo:CMSampleTimingInfo = CMSampleTimingInfo( | |
duration: CMTimeMake(1,30), | |
presentationTimeStamp: self.PTS, | |
decodeTimeStamp: kCMTimeInvalid | |
) | |
var videoFormatDescription:CMVideoFormatDescription? = nil | |
var status = CMVideoFormatDescriptionCreateForImageBuffer( | |
kCFAllocatorDefault, | |
imageBuffer, | |
&videoFormatDescription | |
) | |
var sampleBuffer:CMSampleBuffer? = nil | |
status = CMSampleBufferCreateForImageBuffer( | |
kCFAllocatorDefault, | |
imageBuffer, | |
true, | |
nil, | |
nil, | |
videoFormatDescription!, | |
&timingInfo, | |
&sampleBuffer | |
) | |
//if status != 0{ | |
if let buffer:CMSampleBuffer = sampleBuffer { | |
rtmpStream.appendSampleBuffer(buffer, withType: .video); | |
} | |
//} | |
//increment our timestamp | |
self.PTS = CMTimeAdd(self.PTS, CMTimeMake(1, 30)); | |
} | |
} | |
//// UTIL... | |
func pixelBufferFromImage(image: UIImage) -> CVPixelBuffer { | |
let ciimage = CIImage(image: image) | |
let cgimage = convertCIImageToCGImage(inputImage: ciimage!) | |
/* | |
NSDictionary *options = @{(id)kCVPixelBufferCGImageCompatibilityKey: @YES, | |
(id)kCVPixelBufferCGBitmapContextCompatibilityKey: @YES}; | |
*/ | |
// stupid CFDictionary stuff | |
let cfnumPointer = UnsafeMutablePointer<UnsafeRawPointer>.allocate(capacity: 1) | |
let cfnum = CFNumberCreate(kCFAllocatorDefault, .intType, cfnumPointer) | |
let keys: [CFString] = [kCVPixelBufferCGImageCompatibilityKey, kCVPixelBufferCGBitmapContextCompatibilityKey, kCVPixelBufferBytesPerRowAlignmentKey] | |
let values: [CFTypeRef] = [kCFBooleanTrue, kCFBooleanTrue, cfnum!] | |
let keysPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 1) | |
let valuesPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 1) | |
keysPointer.initialize(to: keys) | |
valuesPointer.initialize(to: values) | |
let options = CFDictionaryCreate(kCFAllocatorDefault, keysPointer, valuesPointer, keys.count, nil, nil) | |
let width = cgimage!.width | |
let height = cgimage!.height | |
// let pxbuffer = UnsafeMutablePointer<CVPixelBuffer?>.allocate(capacity: 1) | |
var pxbuffer: CVPixelBuffer? | |
// if pxbuffer = nil, you will get status = -6661 | |
var status = CVPixelBufferCreate(kCFAllocatorDefault, width, height, | |
kCVPixelFormatType_32ARGB, options, &pxbuffer) | |
debugPrint("status = \(status)") | |
// status = CVPixelBufferLockBaseAddress(pxbuffer.pointee!, CVPixelBufferLockFlags(rawValue: 0)); | |
status = CVPixelBufferLockBaseAddress(pxbuffer!, CVPixelBufferLockFlags(rawValue: 0)); | |
// let bufferAddress = CVPixelBufferGetBaseAddress(pxbuffer.pointee!); | |
let bufferAddress = CVPixelBufferGetBaseAddress(pxbuffer!); | |
// debugPrint("pxbuffer.memory = \(pxbuffer.pointee)") | |
debugPrint("pxbuffer.memory = \(pxbuffer)") | |
let rgbColorSpace = CGColorSpaceCreateDeviceRGB(); | |
//debugPrint("rgbColorSpace = \(rgbColorSpace)") | |
// let bytesperrow = CVPixelBufferGetBytesPerRow(pxbuffer.pointee!) | |
let bytesperrow = CVPixelBufferGetBytesPerRow(pxbuffer!) | |
let context = CGContext(data: bufferAddress, | |
width: width, | |
height: height, | |
bitsPerComponent: 8, | |
bytesPerRow: bytesperrow, | |
space: rgbColorSpace, | |
bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue); | |
//debugPrint("context = \(context.debugDescription)") | |
context?.draw(cgimage!, in: CGRect(x:0, y:0, width:CGFloat(width), height:CGFloat(height))); | |
// status = CVPixelBufferUnlockBaseAddress(pxbuffer.pointee!, CVPixelBufferLockFlags(rawValue: 0)); | |
status = CVPixelBufferUnlockBaseAddress(pxbuffer!, CVPixelBufferLockFlags(rawValue: 0)); | |
return pxbuffer!; | |
} | |
func convertCIImageToCGImage(inputImage: CIImage) -> CGImage!{ | |
let context = CIContext(options: nil) | |
return context.createCGImage(inputImage, from: inputImage.extent) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment