视频采集完成后,需要先编码,再传输,在解码,再播放(重现)
1 视频压缩
第一: 创建VTCompressionSession
———————————— 初始化编码器——————————————————————————
//像素缓冲区选项
letpixelBufferOptions: [String:Any] = [
kCVPixelBufferPixelFormatTypeKeyasString: kCVPixelFormatType_32BGRA,
kCVPixelBufferWidthKeyasString: frameW,
kCVPixelBufferHeightKeyasString: frameH,
kCVPixelBufferOpenGLESCompatibilityKeyasString:true,
kCVPixelBufferIOSurfacePropertiesKeyasString: [:]
]
varerr: OSStatus = noErr
// 初始化编码器
err = VTCompressionSessionCreate(
allocator: kCFAllocatorDefault,
width: Int32(frameW),
height: Int32(frameH),
codecType: codecType,
encoderSpecification: encoderSpecificationsasNSDictionary?,
imageBufferAttributes: pixelBufferOptionsasNSDictionary?,
compressedDataAllocator:nil,
outputCallback: vtCallback,
refcon: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
compressionSessionOut: &sessionOut)
第二: 配置VTCompressionSession
—————————————— 配置VTCompressionSession ———————————
varerr: OSStatus = noErr
使用VTSessionSetProperty
//设置编码方式
err = VTSessionSetProperty(
session,
key: kVTCompressionPropertyKey_ProfileLevel,
value: profileLevel)
第三: 对硬件捕获到的数据进行编码
————————————————对硬件捕获到的数据进行编码 ———————————————
//进行硬编码
varsessionOut: VTCompressionSession?
VTCompressionSessionPrepareToEncodeFrames(session)
第四:VTCompressionOutputCallback
--------------------------------- -----帧压缩完成时调用的回调原型------------------------------------
//////// 压缩输出回调
// 编码完成回调
// 指针对象转换
letenc = unsafeBitCast(outputCallbackRefCon, to: VTEncode.self)
时间信息。我们可以分别使用 CMSampleBufferGetPresentationTimeStamp 和 CMSampleBufferGetDecodeTimeStamp 获得原始演示时间和解码时间的准确时间戳。
// 获取当前帧 是否是关键帧
发送 SPS 和 PPS
CMVideoFormatDescriptionGetH264ParameterSetAtIndex 取得 SPS 和 PPS
compressionSessionOutput 压缩会话输出
CMBlockBufferGetDataPointer (除了关键帧 其他帧只有一个数据)
先找到PAT表, 通过PAT 找到PMT 的表,然后找到了TS流。
只有视频转换TS流。
TS 数据包
TS packet 是TS流的基本组成单位
TS packet 一般是188个字节长度,(或者是204个字节 188个字节加上16个字节(CRC校验数据 ))
TS packet 包含4个字节的 TS header 和其余的TS数据:
4字节 Packet header
184字节 Packet data
PID 唯一标识 ,Packet header 中PID是0x0000, data就为 DVB的PAT标
TS 文件是传输文件,视频编码主要格式h264/mpeg4,音频为acc/MP3。
TS流主要用于相对有错的环境下的传输和存储,如DVB
TS流
先找到PAT表, 通过PAT 找到PMT 的表,然后找到了TS流。
PAT表: 指明了 PMT表的PID值
PMT表: 指明的是音视频流的PID值
pcr 是递增的, 可以将其设置为dts值, 音频数据不需要pcr 。
Pes层 是在每一个视频/音频上加入了时间等信息,pes包内容很多, 只留下最常用的。
转载文档: https://blog.csdn.net/shj348794/article/details/25004783
帧压缩时调用的回调原型 1帧后会异步调用改方法。
// 获取sps pps 数据 只需获取一次,保存在H264文件开头即可。
vps: 仅在H265编码器中才有。
https://blog.csdn.net/weixin_34362790/article/details/91470636
kCMSampleAttachmentKey_DependsOnOthers 通过他判断是否有I帧
1 准备编码器
(1)创建session : VTCompressionSessionCreate
(2)设置属性: VTSessionSetProperty 是否实时编码输出、是否产生B帧、设置关键帧、设置期望帧率、设置码率、最大码率值等等
(3)准备开始编码:VTCompressionSessionPrepareToEncodeFrames
2 编码完成后数据处理
(1)判断是否是关键帧
(2)组装NALU数据: 获取编码后的h264流数据:CMBlockBufferRef dataBuffer = CMSampleBufferGetDataBuffer(sampleBuffer),通过 首地址 、单个长度、 总长度通过dataPointer指针偏移做遍历
OSStatus statusCodeRet = CMBlockBufferGetDataPointer(dataBuffer, 0, &length, &totalLength, &dataPointer);
读取数据时有个大小端模式:网络传输一般都是大端模式
sps:序列参数集
pps:图像参数集
这两个帧也是独立。
添加startcode: 00 00 00 01 然后推流出去。
转载: https://www.cnblogs.com/edisongz/p/7062098.html
H.264 原始流 是由一个一个NALU组成的。
最后输出 compressionSessionOutput 压缩会话
流程总结:
1. 通过VTCompressionSessionCreate创建编码器
2. 通过VTSessionSetProperty设置编码器属性
3. 调用VTCompressionSessionPrepareToEncodeFrames 准备编码
4. 输入采集到的视频数据CVImageBufferRef /CVPixelBufferRef,调用VTCompressionSessionEncodeFrame进行编码
5. 获取到编码后的数据进行处理并组装NALU
NALU分为两种格式: Annex B 和 AVCC
6. 调用VTCompressionSessionCompleteFrames 停止编码器
7. 调用VTCompressionSessionInvalidate销毁编码器
网友评论