0%

FFMPEG系列之五:H264视频流直播

这篇应该暂时是FFMPEG系统的收官之作了,要做的事情很简单:把编码得到的(置于MP4容器中的)H264视频流的AVPacket(见系列第3篇:http://www.spirithy.com/2016/11/13/ffmpeg_third/)通过网络发送到另一端,然后另一端通过解码器decode(见系列第2篇,官方示例中的video_decode_example:http://www.spirithy.com/2016/11/10/ffmpeg_second/),得到图像并展示。

原理和代码都很简单,写完之后在接收端,解码时就开始报错了:

1
2
3
4
5
non-existing PPS 0 referenced
decode_slice_header error
non-existing PPS 0 referenced
decode_slice_header error
no frame!
搜索资料得知,报这个错的原因是发送的H264 AVPacket里面没有包含SPS(Sequence Parameter Sets)和PPS(Picture Parameter Set)。在H264中,SPS和PPS存在于NALU header中,而在MP4容器中,SPS和PPS存在于AVCDecoderConfigurationRecord中。当然这些专业的知识我也不是特别明白,总之大意是MP4容器中的H264 AVPacket不包含SPS和PPS,这些信息被放置到了容器头部里面,所有解码器缺少这些参数无法解码。

再继续搜索资料,大部分资料都提到了使用“h264_mp4toannexb”这个filter来处理AVPacket,可以使它重新带上SPS和PPS。于是在发送端的代码里面,在发送之前用“h264_mp4toannexb”对AVPacket进行了一次处理,但处理时总是报错:

1
Packet header is not contained in global extradata, corrupted stream or invalid MP4/AVCC bitstream
这下又进入了挠头阶段,看到有些资料提到SPS和PPS信息存在于AVCodecContext的extradata字段中,于是尝试着把AVCodecContext的extradata直接复制到了发送出去的AVPacket的字节流前面,这个时候接收端不报解码错误了,正在欣喜呢,接收端又报出了这个错误:
1
concealing 655 DC, 655 AC, 655 MV errors in P frame
这个错误大意是P帧也就是关键帧有错误... 因此又做了无用功。  

几乎要放弃的时候,看着之前的错误信息:"Packet header is not contained in global extradata",想起前面的AVCodecContext不都设置过一个GLOBAL HEADER吗?!

1
pCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
那把这行代码去掉会怎么样呢?

去掉之后,果然,接收端解码全部成功了! 只是发送端会报个warning,大意是容器格式要求使用Global Header但流的AVCodecContext上未设置Global Header,但生成的视频完全不受影响仍然可以正常播放!  

其实这次只是因为一个特殊需求因此做了一个“直播”的Demo,正常情况下完成这个需求一般是使用RTSP/RTMP等。音视频这些东西,不研究清楚了,还真是难以下手呢。