报错的函数:
sws_getContext()
因为参数出了问题,比如宽高信息不对。
但其实是下面这个函数引起的,它会首先解码以小部分数据,但后得到编码和流的信息,如果如果设置的码流探测内存小,或者时间短,这个函数有可能得不到全部的信息,比如宽高等。
avformat_find_stream_info
这个问题是码流探测时没有获取到足够的信息,如视频的width和height。
可以根据提示增加码流探测时间,或者码流探测缓冲区大小。
av_dict_set(&options, “probesize”, “6048000”, 0);//后面这个是byte,要根据流的比特率设置,码流探测时接收到的流放在这个缓冲区。
//av_dict_set(&options, “max_analyze_duration”, “1000000”, 0);//这种方法在ffmpeg6.0中无法生效
ic->max_analyze_duration = 10 * AV_TIME_BASE; avformat_find_stream_info(ic, NULL);
如果这两个需要设置很大才能获取到码流信息,比如5s那么需要考虑传输过来的流是否在网络中丢包严重,或者发送端机器性能问题导致流编码和封装有问题,这个探测时间花费多少s,就相当于凭空多了多少s延时。
如果是udp传输,记得加上1316字节设置,不然即使本机传输,也有大量丢包。
ffmpeg -re -i westLife.mp4 -f mpegts udp://127.0.0.1:5000?pkt_size=1316
补:这个缓冲区的内容也可以设置为只参数码流分析不参与解码,这样码流探测时间就不会带来延时:
ic->flags |= AVFMT_FLAG_NOBUFFER; re = avformat_find_stream_info(ic, NULL);
目前笔者测试这个没有见到效果,且用了之后延时更大。
ffmpeg在接收流时会维护三个缓冲区,除了上面的探测缓冲区A外,还有接收缓冲区B,也就是av_read_frame读的那个缓冲区,还有一个就是解码缓冲区C,也就是下面这个函数设置的缓冲区:
av_opt_set(decodec_ctx_v->priv_data, "tune", "zerolatency", 0);
以下是设置接收缓冲区B的代码:
av_dict_set(&options, "buffer_size", "3554432", 0); av_dict_set(&options, "fifo_size", "3554432", 0);//200Mb
这些key+value值都可以用在命令中的,只需要改成:-key value就可以了,如-buffer_size 3554432 -tune zerolatency等。
这个还需要结合系统的socket和udp分配的内存大小,参考:修改udp的缓冲区大小
关于udp推流还有一些key和value,如下:
buffer_size=size
Set the maximum UDP socket buffer size in bytes.
fifo_size=units
Set the UDP receiving circular buffer size, expressed as a number of packets with size of 188 bytes. If not specified defaults to 7*4096.
overrun_nonfatal=1|0
Survive in case of UDP receiving circular buffer overrun. Default value is 0.
Watch a stream over UDP, with a max reordering delay of 0.5 seconds:
ffplay -max_delay 500000 -rtsp_transport udp rtsp://server/video.mp4
收到udp流后还需要排序,max_delay设置最大排序时间
overrun_nonfatal=1|0
Survive in case of UDP receiving circular buffer overrun. Default value is 0.
当缓冲区满了以后是否崩掉,默认崩掉。
在ffmpeg官方文档http://ffmpeg.org/ffmpeg-all.html可以查看
rtbufsize
减少采集缓存
av_dict_set(&p_device_options,“rtbufsize”,str_buf_size,0);
rtbufsize是缓存的大小,摄像头和麦克风的数据采集出来之后会先放到这个buf中然后才能取出来做解码或编码,buf大小根据自己的需求算出来设定。
audio_buffer_size
减少音频采集sampels数量
av_dict_set(&p_device_options, “audio_buffer_size”,“30”, 0);
音频采集如果不设置一般是采集出来1920个samples,如果没记错android采集出来的samples更多应该超过10000个,这么多的samples做编码的时候aac格式需要1024个samples,循环编完之后才能再次去取新的麦克风数据,所以需要减少。