标题:Qt/C++音视频开发67-保存裸流加入sps/pps信息/支持264/265裸流/转码保存/拉流推流
作者:liudianwu
日期:2024-03-03 08:46
内容:
## 一、前言
音视频组件除了支持保存MP4文件外,同时还支持保存裸流即264/265文件,以及解码后最原始的yuv文件。在实际使用过程中,会发现部分视频文件保存的裸流文件,并不能直接用播放器播放,查阅资料得知原来是缺少sps/pps信息,监控行业的rtsp/rtmp/录像mp4文件都是会带的,所以很少遇到这个现象。其实sps/pps信息在解码的时候就已经在对应AVCodecContext或者AVStream的extradata中,只是在av_read_frame后的AVPacket,有些流带了sps/pps而有些流就没带,没带的就需要主动加上。那如果带了也又加上,会不会出问题呢?答案是不会的,在执行av_bsf_send_packet/av_bsf_receive_packet的时候里面会自动过滤判断。测试下来发现,只有裸流才需要加入,如果是原数据或者编码数据保存到MP4文件则不需要,因为在创建MP4流的时候就已经复制了原始流的参数,那个参数中就包含了extradata,所以在写入数据的时候就会自动加上。保存裸流到文件这个需求也是有的,尤其是现在人工智能分析,基本上需要传入264/265裸流进行运算分析,音频传输pcm数据。
在h264流中,有两种NALU极其的重要,序列参数集(Sequence Paramater Set,SPS)和图像参数集(Picture ParamaterSet,PPS),SPS中的信息至关重要,记录了编码的prfile、level、图像宽高等,如果其中的数据丢失或出现错误,那么解码过程很可能会失败。每一帧编码后数据所依赖的参数保存于PPS中。一般情况SPS和PPS的NAL Unit通常位于整个码流的起始位置。封装文件一般进保存一次,位于文件头部,sps/sps再整个解码过程中复用,不发生变化。然而对于实时流,通常是从流中间开始解码,因此需要在每个I帧前添加SPS和PPS;如果编码器在编码过程中改变了码流参数(如分辨率),需要重新调整SPS和PPS数据。
ffmpeg中SPS、PPS数据从输入流中解析时,位于AVFormatContext->streams->codecpar->extradata中。编码时,sps/pps数据存放于编码器上下文AVCodecContext->extradata中,但是该对象通常是空指针,还需要进行额外设置。通常我们编码保存裸流时,仅第一个I帧前有SPS/PPS数据。但是,如果需要做实时流传输,必须要在每一个I帧前添加SPS和PPS。其中SPS和PPS分别是14/5个字节。
有两种方法可以加上sps/pps,一种是自己判断并主动加上,一种是用ffmpeg自带的bsf相关函数,推荐使用bsf相关函数处理,非常准确而且性能高。一开始我也以为很难,其实非常简单,总结就是三步走,初始化,不 ..