编解码协议H264(视频)和AAC(音频)有软编解码和硬编解码。
网络传输都是用的大端序(高地址低字节),H264网络传输的startcode是数据的length,不是0x00000001。NALU 有两种格式:Annex B 和 AVCC。Annex B 格式startcode以 0x 00 00 01 或 0x 00 00 00 01 开头, AVCC 格式以 NALU 的长度开头。
AAC也有两种传输格式:ADTS和ADIF
- ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。
- ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。
软编码:使用CPU进行编码。编码框架ffmpeg+x264。
- https://www.jianshu.com/p/e631b041e96d
- https://www.jianshu.com/p/3de01105d735
硬编码:不使用CPU进行编码,使用显卡(GPU)进行硬件加速。 专用的DSP、FPGA、ASIC芯片等硬件进行编码。ios上硬编码框架Video ToolBox和AudioToolbox。
- Intel硬编码使用Intel处理器内部集成的显卡进行硬件加速,qsv加速方法便对应着Intel硬编码。Intel硬编码对H.264加速效果明显,且不需要安装额外库(仅使用相应的ffmpeg命令)。
- NVIDIA硬编码使用英伟达的显卡对视频编码进行加速。CUDA加速方法对应着NVIDIA硬编码。使用英伟达硬编码之前需要安装CUDA与英伟达的必要驱动。安装好两个环境后就可以使用NVIDIA的硬编码了。英伟达关于视频的编解码提供了两个相关的 SDK:NVENC(硬编码)和NVCUVID(硬解码),前者负责硬件编码,二后者负责硬件解码。CUDA支持Windows、Linux、MacOS三种主流操作系统。https://blog.csdn.net/qq_29350001/article/details/75144665(CUDA详解)
- FFmpeg中也支持了硬编码,集成了显示视频处理模块。在命令行中使用 ffmpeg -hwaccels 可以查看ffmpeg支持的硬件加速方法。
FFMPEG 目前存在一个编码器 nvenc 是对于NVIDIA的 NVENC 的封装,通过使用它可以和 FFMPEG 无缝的整合起来。不过 FFMPEG 只存在 NVENC 的接口,不存在 NVCUVID(解码器) 的封装。如果需要实现相关的解码器可能需要自己实现 FFMPEG 接口。FFMPEG实现了对于 Intel QSV 的封装。 - DXVA是微软定制的视频加速规范、在Linux 平台上则是由NVIDIA提供的VDPAU和Intel提供的VAAPI加速规范。
在不同平台上可通过不同API使用Intel GPU的硬件加速能力。目前主要由两套API:VAAPI以及libmfx。VAAPI (视频加速API,Video Acceleration API)包含一套开源的库(LibVA) 以及API规范, 用于硬件加速下的视频编解码以及处理,只有Linux上的驱动提供支持。libmfx。Intel Media SDK中的API规范,支持视频编解码以及媒体处理。支持Windows以及Linux。除了Intel自己的API,在Windows系统上还有其他API可使用Intel GPU的硬件加速能力,这些API属于Windows标准,由Intel显卡驱动实现。DXVA2 / D3D11VA。标准Windows API,支持通过Intel显卡驱动进行视频编解码,FFmpeg有对应实现。Media Foundation。标准Windows API,支持通过Intel显卡驱动进行视频编解码,FFmpeg不支持该API。https://blog.jianchihu.net/intel-gpu-hw-video-codec-develop.html
目前的主流GPU加速平台:
INTEL、AMD、NVIDIA
目前主流的GPU平台开发框架:
- CUDA:NVIDIA的封闭编程框架,通过框架可以调用GPU计算资源
- AMD APP:AMD为自己的GPU提出的一套通用并行编程框架,标准开放,通过在CPU、GPU同时支持OpenCL框架,进行计算力融合。
- OpenCL:开放计算语言,为异构平台编写程序的该框架,异构平台可包含CPU、GPU以及其他计算处理器,目标是使相同的运算能支持不同平台硬件加速。
- Inel QuickSync:集成于Intel显卡中的专用视频编解码模块。
https://www.jianshu.com/p/8423724dffc1
https://blog.csdn.net/haowei0926/article/details/56012139
ios中的硬编码文档
ios上硬编码框架Video ToolBox和AudioToolbox。Video ToolBox是一个底层框架,可以直接访问硬件编码器和解码器。 它提供视频压缩和解压缩服务,并在CoreVideo像素缓冲区中存储的光栅raster图像格式之间进行转换。 这些服务以会话对象(压缩,解压缩和像素传输)的形式提供,它们以Core Foundation(CF)类型呈现。 不需要直接访问硬件编码器和解码器的应用程序App就不需要直接使用VideoToolbox。iOS 8.0及以上苹果开放了VideoToolbox框架来实现H264硬编码(H264是一种编解码协议,有多种编解码器能编解码H264,这里是利用硬件进行编解码,FFmpeg中可以利用硬编解码和软编解码)。
- CVPixelBufferRef/CVImageBufferRef:存放编码前和解码后的图像数据(未压缩的数据),这两个是相同的对象。
- CMTime:时间戳相关,时间以64-bit/32-bit的形式出现
- CMBlockBufferRef:编码后输出的数据(压缩后的数据)
- CMFormatDescriptionRef/CMVideoFormatDescriptionRef:图像存储方式,编解码器等格式描述。这两个是相同的对象。
- CMSampleBufferRef:存放编解码前后的视频图像的容器数据,iOS中表示一帧音频/视频数据
- CMSampleBuffer 可能是一个压缩的数据,也可能是一个未压缩的数据。取决于 CMSampleBuffer 里面是 CMBlockBuffer(压缩后) 还是 CVPixelBuffer(未压缩)。
硬编码的步骤 :从相机或读取视频文件输出的CVPixelBuffer(也是以CMSampleBufferRef封装形式存在)—>Encoder—>CMSampleBufferRef(编码后得到的数据封装)—>重新组装NALUs。
- 通过VTCompressionSessionCreate创建编码器
VTCompressionSessionCreate( CM_NULLABLE CFAllocatorRef allocator, int32_t width, int32_t height, CMVideoCodecType codecType, CM_NULLABLE CFDictionaryRef encoderSpecification, CM_NULLABLE CFDictionaryRef sourceImageBufferAttributes, CM_NULLABLE CFAllocatorRef compressedDataAllocator, CM_NULLABLE VTCompressionOutputCallback outputCallback, void * CM_NULLABLE outputCallbackRefCon, CM_RETURNS_RETAINED_PARAMETER CM_NULLABLE VTCompressionSessionRef * CM_NONNULL compressionSessionOut) allocator:内存分配器,填NULL为默认分配器 width、height:视频帧像素的宽高,如果编码器不支持这个宽高的话可能会改变 codecType:编码类型,枚举 encoderSpecification:指定特定的编码器,填NULL的话由VideoToolBox自动选择 sourceImageBufferAttributes:源像素缓冲区的属性,如果这个参数有值的话,VideoToolBox会创建一个缓冲池,不需要缓冲池可以设置为NULL compressedDataAllocator:压缩后数据的内存分配器,填NULL使用默认分配器 outputCallback:视频编码后输出数据回调函数 outputCallbackRefCon:回调函数中的自定义指针,我们通常传self,因为我们需要在C函数中调用self的方法,而C函数无法直接调self, compressionSessionOut:编码器句柄,传入编码器的指针
- 通过VTSessionSetProperty设置编码器属性,是否实时编码输出、是否产生B帧、设置关键帧、设置期望帧率、设置码率、最大码率值等等。
VTSessionSetProperty( // 解码会话 CM_NONNULL VTSessionRef session, // 属性 KEY CM_NONNULL CFStringRef propertyKey, // 设置的属性值 CM_NULLABLE CFTypeRef propertyValue ) kVTCompressionPropertyKey_AverageBitRate:设置编码的平均码率,单位是bps,这不是一个硬性指标,设置的码率会上下浮动。VideoToolBox框架只支持ABR模式。H264有4种码率控制方法: CBR(Constant Bit Rate)是以恒定比特率方式进行编码,有Motion发生时,由于码率恒定,只能通过增大QP来减少码字大小,图像质量变差,当场景静止时,图像质量又变好,因此图像质量不稳定。这种算法优先考虑码率(带宽)。 VBR(Variable Bit Rate)动态比特率,其码率可以随着图像的复杂程度的不同而变化,因此其编码效率比较高,Motion发生时,马赛克很少。码率控制算法根据图像内容确定使用的比特率,图像内容比较简单则分配较少的码率(似乎码字更合适),图像内容复杂则分配较多的码字,这样既保证了质量,又兼顾带宽限制。这种算法优先考虑图像质量。 *CVBR(Constrained VariableBit Rate),这样翻译成中文就比较难听了,它是VBR的一种改进方法。但是Constrained又体现在什么地方呢?这种算法对应的Maximum bitRate恒定或者Average BitRate恒定。这种方法的兼顾了以上两种方法的优点:在图像内容静止时,节省带宽,有Motion发生时,利用前期节省的带宽来尽可能的提高图像质量,达到同时兼顾带宽和图像质量的目的。 ABR (Average Bit Rate) 在一定的时间范围内达到设定的码率,但是局部码率峰值可以超过设定的码率,平均码率恒定。可以作为VBR和CBR的一种折中选择。 kVTCompressionPropertyKey_ProfileLevel:设置H264编码的画质,H264有4种Profile:BP、EP、MP、HP BP(Baseline Profile):基本画质。支持I/P 帧,只支持无交错(Progressive)和CAVLC;主要应用:可视电话,会议电视,和无线通讯等实时视频通讯领域 EP(Extended profile):进阶画质。支持I/P/B/SP/SI 帧,只支持无交错(Progressive)和CAVLC; MP(Main profile):主流画质。提供I/P/B 帧,支持无交错(Progressive)和交错(Interlaced),也支持CAVLC 和CABAC 的支持;主要应用:数字广播电视和数字视频存储 HP(High profile):高级画质。在main Profile 的基础上增加了8×8内部预测、自定义量化、 无损视频编码和更多的YUV 格式;应用于广电和存储领域 Level就多了,这里不一一列举,可参考h264 profile & level,iPhone上常用的方案如下: 实时直播: 低清Baseline Level 1.3 标清Baseline Level 3 半高清Baseline Level 3.1 全高清Baseline Level 4.1 存储媒体: 低清 Main Level 1.3 标清 Main Level 3 半高清 Main Level 3.1 全高清 Main Level 4.1 高清存储: 半高清 High Level 3.1 全高清 High Level 4.1 kVTCompressionPropertyKey_RealTime:设置是否实时编码输出 kVTCompressionPropertyKey_AllowFrameReordering:配置是否产生B帧,High profile 支持 B 帧 kVTCompressionPropertyKey_MaxKeyFrameInterval、kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration:配置I帧间隔
- 调用VTCompressionSessionPrepareToEncodeFrames准备编码
VTCompressionSessionPrepareToEncodeFrames( CM_NONNULL VTCompressionSessionRef session ) session:编码器句柄,传入编码器的指针
- 输入采集到的视频数据CVImageBufferRef /CVPixelBufferRef,调用VTCompressionSessionEncodeFrame进行编码
VTCompressionSessionEncodeFrame( CM_NONNULL VTCompressionSessionRef session, CM_NONNULL CVImageBufferRef imageBuffer, CMTime