FFmpeg 直播黑屏问题分析解决

    • 背景
    • 分析思路
    • 解决思路

背景

FFmpeg是非常优秀的开源框架,在使用其进行二次开发及适配的过程中,难免会遇到各种各样的问题。
这次记录的是基于FFmpeg开发的播放器中,直播黑屏问题分析思路及解决方法。本文不涉及详细的代码流程,主要是提供分析思路。
问题如下:
在直播节目的使用过程中,某些播放源起播后画面黑屏,但却有声音,直播节目基于HLS。

分析思路

对于这类问题的分析,需要获取网络包和对应的日志,才能更好地定位问题原因。
分析步骤如下:
1、确认流的格式,确保流本身正常,视频编码方式可以支持。
可以在代码中dump流,或者直接从网络包中过滤去响应的媒体流,我更倾向于第二种。
流可以用PC端的VLC播放,可以明确流本身并无问题。同时查看编解码信息,确认这种视频格式我们是支持的(工具->编解码器信息,截图只是示例,不是出问题的流)
FFmpeg 直播黑屏问题分析解决_第1张图片
2、查看FFmpeg是否解析出正确的音视频格式。
我们可以在av_find_stream_info函数之后,使用av_dump_format函数将音视频信息dump出来,来确认FFmpeg是否解析正确。
可以看到,音频(PID[0xb3]),其相应信息已经解析出来Audio: mp2, 48000 Hz, stereo, s16, 192 kb/s
而另一个数据(PID[0xb2]),则具体信息并不清楚。

03-28 09:17:55.073 I/ffmpeg( 3431):   Duration: 
03-28 09:17:55.073 I/ffmpeg( 3431): N/A
03-28 09:17:55.073 I/ffmpeg( 3431): , start: 
03-28 09:17:55.073 I/ffmpeg( 3431): 75309.284411
03-28 09:17:55.073 I/ffmpeg( 3431): , bitrate: 
03-28 09:17:55.073 I/ffmpeg( 3431): N/A
03-28 09:17:55.073 I/ffmpeg( 3431): 
03-28 09:17:55.073 I/ffmpeg( 3431):   Program 5 
03-28 09:17:55.073 I/ffmpeg( 3431):     Metadata:
03-28 09:17:55.073 I/ffmpeg( 3431):       service_name    : CCTV2 HD
03-28 09:17:55.073 I/ffmpeg( 3431):   No Program
03-28 09:17:55.083 I/ffmpeg( 3431):     Stream #0.0
03-28 09:17:55.083 I/ffmpeg( 3431): [0xb2]
03-28 09:17:55.083 I/ffmpeg( 3431): : Data: [0][0][0][0] / 0x0000
03-28 09:17:55.083 I/ffmpeg( 3431): 
03-28 09:17:55.083 I/ffmpeg( 3431):     Stream #0.1
03-28 09:17:55.083 I/ffmpeg( 3431): [0xb3]
03-28 09:17:55.083 I/ffmpeg( 3431): : Audio: mp2, 48000 Hz, stereo, s16, 192 kb/s
03-28 09:17:55.083 I/ffmpeg( 3431): 

3、使用TS解析工具解析并对比正常播放的流,可以看到正常播放时dump信息中,video信息已经解析出来,TS解析工具中,PID[0xb2]也即是视频PID。所以基本可以确定是FFmpeg没有正确解析PMT表。

03-28 09:18:51.983 I/ffmpeg( 3431): N/A
03-28 09:18:51.983 I/ffmpeg( 3431): , start: 
03-28 09:18:51.983 I/ffmpeg( 3431): 75369.524411
03-28 09:18:51.983 I/ffmpeg( 3431): , bitrate: 
03-28 09:18:51.983 I/ffmpeg( 3431): N/A
03-28 09:18:51.983 I/ffmpeg( 3431): 
03-28 09:18:51.983 I/ffmpeg( 3431):   Program 5 
03-28 09:18:51.983 I/ffmpeg( 3431):     Stream #0.0
03-28 09:18:51.983 I/ffmpeg( 3431): [0xb2]
03-28 09:18:51.983 I/ffmpeg( 3431): : Video: h264 (High), 1920x1088
03-28 09:18:51.983 I/ffmpeg( 3431): , 90k tbr
03-28 09:18:51.983 I/ffmpeg( 3431): , 90k tbn
03-28 09:18:51.983 I/ffmpeg( 3431): 
03-28 09:18:51.983 I/ffmpeg( 3431):     Stream #0.1
03-28 09:18:51.983 I/ffmpeg( 3431): [0xb3]
03-28 09:18:51.983 I/ffmpeg( 3431): (eng)
03-28 09:18:51.983 I/ffmpeg( 3431): : Audio: mp2, 48000 Hz, stereo, s16, 192 kb/s

4、结合代码分析。
对于TS流PAT/PMT表的解析,也即是demux的流程了,该流程在avformat_open_input中。
查看mpegts对应的demux模块。对于avformat_open_input流程,一般是调用read_head函数,即mpegts_read_header。

AVInputFormat ff_mpegts_demuxer = {
    "mpegts",
    NULL_IF_CONFIG_SMALL("MPEG-2 transport stream format"),
    sizeof(MpegTSContext),
    mpegts_probe,
    mpegts_read_header,
    mpegts_read_packet,
    mpegts_read_close,
    .read_seek = mpegts_read_seek,
    .read_timestamp = mpegts_get_dts,
    .flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT| AVFMT_GENERIC_INDEX,
};

可以看到,为了加快起播速度,probe_size 设置的较小(256kB),handle_packets函数会根据设置的probe_size,读取一定数量的ts包进行解析,这就造成一种情况,可能读取不到PAT表。

static int mpegts_read_header(AVFormatContext *s,
                              AVFormatParameters *ap)
{
   ....省略
            //find PMT, would stop parse
			 probe_size =256 * 1024;//fast play
			 handle_packets(ts, probe_size / ts->raw_packet_size);
   ....省略
        }

5、使用EasyICE分析TS切片。
256kB对应的偏移量为0x40000,拿m3u8中第一个下载的分片(注意是第一个下载的分片,不是列表中的第一个,因为不一定从头开始下载)。
使用EasyICE分析,可以看到,PAT表偏移为0x6C3A8,大于0x40000,所以demux阶段,并没有获取到PAT/PMT表,所以无法解析出正确的视频格式。
而音频为什么能解析出来呢,这是因为av_find_stream_info还有弹窗流程,可以解析出音频格式,但视频在这种情况下无法完整解析出来。
FFmpeg 直播黑屏问题分析解决_第2张图片
总结:该问题在于FFmpeg没有读取到PAT/PMT,导致解析错误。原因可能是直播流比较大,这种情况下,媒体数据较大,PSI/SI信息在TS流中占比可能较小,读取太小的数据就可能出错。

解决思路

解析该问题的方法有两种:
1、从客户端解决,即加大demux阶段解析的数据大小,但其实无法保证在流更大或者PSI/SI分布太稀疏的情况下也正常,且网络较差的情况下,起播速度会有一定影响。
2、从CDN解决,媒体服务器在对于HLS协议的直播流,可以在每个分片的最开始插入PSI/SI信息,这样可以保证客户端一定能正确获取。

你可能感兴趣的:(流媒体,FFmpeg)