Closed blackox626 closed 3 months ago
能够提供视频片段让我进行调试吗?你可以上传一分钟以内的小视频到github就可以了。
能够提供视频片段让我进行调试吗?你可以上传一分钟以内的小视频到github就可以了。
我这边业务链接不方便 给到, 不过是不是可以通过 加一个 mp4toannexb filter 来模拟这个case
你可以在网上随便找个视频,然后用ffmpeg转一个Annex-B 格式。这样就可以了
另外我这边 尝试 改了下,发现能播放 渲染出来了。但是视频会卡住。。 还没定位到原因 只考虑了 hevc 的情况 我贴一下代码, swift 不太熟练
class DecoderInfo {
var vps: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)
var sps: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)
var f_pps: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)
var r_pps: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>.allocate(capacity: 1)
var vps_size: Int32 = 0
var sps_size: Int32 = 0
var f_pps_size: Int32 = 0
var r_pps_size: Int32 = 0
}
func getNALUInfo(extraData: UnsafeMutablePointer<UInt8>,extraDataSize: Int32, decoderInfo: DecoderInfo) {
var decoderInfo = decoderInfo
var data = extraData
var size = extraDataSize;
var startCodeVPSIndex : Int32 = 0
var startCodeSPSIndex : Int32 = 0
var startCodeFPPSIndex : Int32 = 0
var startCodeRPPSIndex : Int32 = 0
var nalu_type : Int = 0
for i in 0..<size {
if i >= 3 {
if data[Int(i)] == 0x01 && data[Int(i) - 1] == 0x00 && data[Int(i) - 2] == 0x00 && data[Int(i) - 3] == 0x00 {
if startCodeVPSIndex == 0 {
startCodeVPSIndex = i
continue
}
if i > startCodeVPSIndex && startCodeSPSIndex == 0 {
startCodeSPSIndex = i
continue
}
if i > startCodeSPSIndex && startCodeFPPSIndex == 0 {
startCodeFPPSIndex = i
continue
}
if i > startCodeFPPSIndex && startCodeRPPSIndex == 0 {
startCodeRPPSIndex = i
}
}
}
}
let spsSize = startCodeFPPSIndex - startCodeSPSIndex - 4
decoderInfo.sps_size = spsSize
let vpsSize = startCodeSPSIndex - startCodeVPSIndex - 4
decoderInfo.vps_size = vpsSize
let f_ppsSize = (startCodeRPPSIndex != 0) ? (startCodeRPPSIndex - startCodeFPPSIndex - 4) : (size - (startCodeFPPSIndex + 1))
decoderInfo.f_pps_size = f_ppsSize
nalu_type = Int(data[Int(startCodeVPSIndex) + 1]) & 0x4F
if nalu_type == 0x40 {
let vps =
withUnsafeMutablePointer(to: &data[Int(startCodeVPSIndex) + 1]) {$0}
decoderInfo.vps = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(vpsSize))
memcpy(decoderInfo.vps, vps, Int(vpsSize))
}
nalu_type = Int(data[Int(startCodeSPSIndex) + 1]) & 0x4F
if nalu_type == 0x42 {
let sps =
withUnsafeMutablePointer(to: &data[Int(startCodeSPSIndex) + 1]) {$0}
decoderInfo.sps = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(spsSize))
memcpy(decoderInfo.sps, sps, Int(spsSize))
}
nalu_type = Int(data[Int(startCodeFPPSIndex) + 1]) & 0x4F
if nalu_type == 0x44 {
let fpps =
withUnsafeMutablePointer(to: &data[Int(startCodeFPPSIndex) + 1]) {$0}
decoderInfo.f_pps = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(f_ppsSize))
memcpy(decoderInfo.f_pps, fpps, Int(f_ppsSize))
}
if startCodeRPPSIndex == 0 {
return
}
let r_ppsSize = size - (startCodeRPPSIndex + 1)
decoderInfo.r_pps_size = r_ppsSize
nalu_type = Int(data[Int(startCodeRPPSIndex) + 1]) & 0x4F
if nalu_type == 0x44 {
let rpps =
withUnsafeMutablePointer(to: &data[Int(startCodeRPPSIndex) + 1]) {$0}
decoderInfo.r_pps = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(r_ppsSize))
memcpy(decoderInfo.r_pps, rpps, Int(r_ppsSize))
}
}
if let extradata {
extradataSize = codecpar.extradata_size
/// avcc
// if extradataSize >= 5, extradata[4] == 0xFE {
// extradata[4] = 0xFF
// isConvertNALSize = true
// } else {
// isConvertNALSize = false
// }
// atomsData = Data(bytes: extradata, count: Int(extradataSize))
atomsData = nil
isConvertNALSize = true
getNALUInfo(extraData: extradata, extraDataSize: extradataSize, decoderInfo: decoderInfo)
}
// _ = CMVideoFormatDescriptionCreate(allocator: kCFAllocatorDefault, codecType: codecType.rawValue, width: codecpar.width, height: codecpar.height, extensions: dic, formatDescriptionOut: &formatDescriptionOut)
let parameterSetPointers: [UnsafePointer<UInt8>] = [UnsafePointer<UInt8>(decoderInfo.vps), UnsafePointer<UInt8>(decoderInfo.sps), UnsafePointer<UInt8>(decoderInfo.f_pps)]
let parameterSetSizes: [Int] = [Int(decoderInfo.vps_size), Int(decoderInfo.sps_size), Int(decoderInfo.f_pps_size)]
if #available(iOS 11.0, *) {
let status = CMVideoFormatDescriptionCreateFromHEVCParameterSets(allocator: kCFAllocatorDefault,
parameterSetCount: 3,
parameterSetPointers: parameterSetPointers,
parameterSetSizes: parameterSetSizes,
nalUnitHeaderLength: 4,
extensions: nil,
formatDescriptionOut: &formatDescriptionOut)
} else {
let status = -1
}
let attributes: NSMutableDictionary = [
kCVPixelBufferPixelFormatTypeKey: kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,//pixelFormatType,
kCVPixelBufferMetalCompatibilityKey: true,
kCVPixelBufferWidthKey: assetTrack.codecpar.width,
kCVPixelBufferHeightKey: assetTrack.codecpar.height,
kCVPixelBufferIOSurfacePropertiesKey: NSDictionary(),
]
if isConvertNALSize {
// var ioContext: UnsafeMutablePointer<AVIOContext>?
// let status = avio_open_dyn_buf(&ioContext)
// if status == 0 {
// var nalSize: UInt32 = 0
// let end = data + size
// var nalStart = data
// while nalStart < end {
// nalSize = UInt32(nalStart[0]) << 16 | UInt32(nalStart[1]) << 8 | UInt32(nalStart[2])
// avio_wb32(ioContext, nalSize)
// nalStart += 3
// avio_write(ioContext, nalStart, Int32(nalSize))
// nalStart += Int(nalSize)
// }
// var demuxBuffer: UnsafeMutablePointer<UInt8>?
// let demuxSze = avio_close_dyn_buf(ioContext, &demuxBuffer)
// return try createSampleBuffer(data: demuxBuffer, size: Int(demuxSze))
// } else {
// throw NSError(errorCode: .codecVideoReceiveFrame, avErrorCode: status)
// }
var ioContext: UnsafeMutablePointer<AVIOContext>?
let status = avio_open_dyn_buf(&ioContext)
if status == 0 {
var nalStart = data
var i = 0
var start = 0
while i < size {
if i+2 < size {
if data[i] == 0x00 && data[i+1] == 0x00 && data[i+2] == 0x01 {
if start == 0 {
start = 3
nalStart += 3
} else {
let len = i - start
avio_wb32(ioContext, UInt32(len))
avio_write(ioContext, nalStart, Int32(len))
start = i + 3
nalStart += len + 3
}
//
i+=3
continue
}
}
if i+3 < size {
if data[i] == 0x00 && data[i+1] == 0x00 && data[i+2] == 0x00 && data[i+3] == 0x01 {
if start == 0 {
start = 4
nalStart += 4
} else {
let len = i - start
avio_wb32(ioContext, UInt32(len))
avio_write(ioContext, nalStart, Int32(len))
start = i + 4
nalStart += len + 4
}
//
i+=4
continue
}
}
i += 1
}
let len = size - start
avio_wb32(ioContext, UInt32(len))
avio_write(ioContext, nalStart, Int32(len))
var demuxBuffer: UnsafeMutablePointer<UInt8>?
let demuxSze = avio_close_dyn_buf(ioContext, &demuxBuffer)
return try createSampleBuffer(data: demuxBuffer, size: Int(demuxSze))
} else {
throw NSError(errorCode: .codecVideoReceiveFrame, avErrorCode: status)
}
你可以在网上随便找个视频,然后用ffmpeg转一个Annex-B 格式。这样就可以了
https://assets.weidianfans.com/res/1dc70c36.h264
annexb 格式的 h264 文件
这个视频无法走我自己写的硬接,但是是可以走ffmpeg的硬接的。我自己实现的硬解比较简单,没有适配那么多的情况。所以这个还是会走videotoolbox的
这个视频无法走我自己写的硬接,但是是可以走ffmpeg的硬接的。我自己实现的硬解比较简单,没有适配那么多的情况。所以这个还是会走videotoolbox的
是的 。
//int ff_isom_write_hvcc(AVIOContext pb, const uint8_t data, int size, int ps_array_completeness);
这个方法 也可以处理 annexb extradata 转 hvcc ,自己硬解 也方便很多
你用我的demo会发现它没有走硬解,是因为它是 bottom first。需要走filter
你用我的demo会发现它没有走硬解,是因为它是 bottom first。需要走filter
是的 ,我注释掉了 然后强制走videotoolbox 硬解,复现问题 哈哈
我在lgpl分支支持Annex-B videotoolbox硬解码了
codecpar.extradata 如果是 Annex-B 格式,直接创建 formatDescription ,会导致decompressionSession 创建失败, videotoolbox硬解码走不到