I get h264 in Data format. The video plays well on the simulator. And on a real device intermittently with a hang. I don't use decompression.
class H264Decoder {
var sampleBufferCallback: ((CMSampleBuffer) -> Void)?
private var sps: H264UnitModel?
private var pps: H264UnitModel?
private var description: CMVideoFormatDescription?
private var fullBuffer: CMBlockBuffer?
func decode(_ h264Units: [H264UnitModel]) {
fullBuffer = nil
var isDescript = false
for h264Unit in h264Units {
isDescript = false
if h264Unit.type == .sps || h264Unit.type == .pps {
description = nil
createDescription(with: h264Unit)
isDescript = true
} else {
sps = nil
pps = nil
}
if !isDescript {
guard let fullBuffer = createBlockBuffer(with: h264Unit) else {
return
}
guard let sampleBuffer = createSampleBuffer(with: fullBuffer) else {
return
}
sampleBufferCallback?(sampleBuffer)
}
}
}
// MARK: - create Block Buffer
private func createBlockBuffer(with h264Format: H264UnitModel) -> CMBlockBuffer? {
let pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: h264Format.data.count)
h264Format.data.copyBytes(to: pointer, count: h264Format.data.count)
var blockBuffer: CMBlockBuffer?
let error = CMBlockBufferCreateWithMemoryBlock(allocator: kCFAllocatorDefault,
memoryBlock: pointer,
blockLength: h264Format.data.count,
blockAllocator: kCFAllocatorDefault,
customBlockSource: nil,
offsetToData: 0,
dataLength: h264Format.data.count,
flags: .zero,
blockBufferOut: &blockBuffer)
guard error == kCMBlockBufferNoErr else {
return nil
}
return blockBuffer
}
private func createSampleBuffer(with blockBuffer: CMBlockBuffer) -> CMSampleBuffer? {
var sampleBuffer: CMSampleBuffer?
var timingInfo = CMSampleTimingInfo()
timingInfo.decodeTimeStamp = .invalid
timingInfo.duration = CMTime.invalid
timingInfo.presentationTimeStamp = .zero
let error = CMSampleBufferCreateReady(allocator: kCFAllocatorDefault,
dataBuffer: blockBuffer,
formatDescription: description,
sampleCount: 1,
sampleTimingEntryCount: 1,
sampleTimingArray: &timingInfo,
sampleSizeEntryCount: 0,
sampleSizeArray: nil,
sampleBufferOut: &sampleBuffer)
guard error == noErr,
let sampleBuffer = sampleBuffer else {
return nil
}
if let attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer,
createIfNecessary: true) {
let dic = unsafeBitCast(CFArrayGetValueAtIndex(attachments, 0),
to: CFMutableDictionary.self)
CFDictionarySetValue(dic,
Unmanaged.passUnretained(kCMSampleAttachmentKey_DisplayImmediately).toOpaque(),
Unmanaged.passUnretained(kCFBooleanTrue).toOpaque())
}
return sampleBuffer
}
private func createDescription(with h264Format: H264UnitModel) {
if h264Format.type == .sps {
sps = h264Format
} else if h264Format.type == .pps {
pps = h264Format
}
guard let sps = sps,
let pps = pps else { return }
let spsPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: sps.data.count)
sps.data.copyBytes(to: spsPointer, count: sps.data.count)
let ppsPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: pps.data.count)
pps.data.copyBytes(to: ppsPointer, count: pps.data.count)
let parameterSet = [UnsafePointer(spsPointer), UnsafePointer(ppsPointer)]
let parameterSetSizes = [sps.data.count, pps.data.count]
defer {
parameterSet.forEach {
$0.deallocate()
}
}
let error = CMVideoFormatDescriptionCreateFromH264ParameterSets(allocator: kCFAllocatorDefault,
parameterSetCount: 2,
parameterSetPointers: parameterSet,
parameterSetSizes: parameterSetSizes,
nalUnitHeaderLength: 4,
formatDescriptionOut: &description)
guard error == noErr else {
return
}
}
}
I suspect I'm missing some key to set up the decoding. No errors are output to the console. Receiving status CMBlockBuffer, CMSampleBuffer, CMVideoFormatDescription equal 0.