更新了iOS15.6系统后,发现拉取LFLiveKit进行直播的流,竟然是这样的:
模糊不清,于是思考是什么原因导致的。
1、是不是拉流端出现的问题?
使用安卓拉取iOS的直播流,是同样的效果,又考虑到两端使用的都是IJKPlayer播放器播放的,所以又用VLC进行拉流播放,还是同样的效果,最终排除。
2、 是不是服务端出现的问题?
安卓端推、拉流都是正常,没有问题,而且服务端只是做了一个流转发的过程,没有对数据进行任何处理,所以排出。
3、那只可能是推流端出现了问题。
但是代码是没有改过的,更新系统以后出现了问题,那只能是系统对编码器的参数设置进行了优化,可能是某些地方的参数值不适配或不够精确了。
模糊不清,是不是跟分辨率有关?我首先想到的是提高平均码率值和最小、最大码率值,然后在编码设置时,设置码率限制值,如下:
发现效果不是很明显,于是想是不是跟编码帧设置之前的参数有关,于是我研究了一下这些代码:
因为也有WebRTC的源码,于是进行了对比:
发现 presentationTimeStamp 这个参数的设置是不一样的,于是我按照WebRTC的方式进行修改,发现依然模糊不清。
接着查看源码注释:
/*!
@function VTCompressionSessionEncodeFrame
@abstract
Call this function to present frames to the compression session.
Encoded frames may or may not be output before the function returns.
@discussion
The client should not modify the pixel data after making this call.
The session and/or encoder will retain the image buffer as long as necessary.
@param session
The compression session.
@param imageBuffer
A CVImageBuffer containing a video frame to be compressed.
Must have a nonzero reference count.
@param presentationTimeStamp
The presentation timestamp for this frame, to be attached to the sample buffer.
Each presentation timestamp passed to a session must be greater than the previous one.
@param duration
The presentation duration for this frame, to be attached to the sample buffer.
If you do not have duration information, pass kCMTimeInvalid.
@param frameProperties
Contains key/value pairs specifying additional properties for encoding this frame.
Note that some session properties may also be changed between frames.
Such changes have effect on subsequently encoded frames.
@param sourceFrameRefcon
Your reference value for the frame, which will be passed to the output callback function.
@param infoFlagsOut
Points to a VTEncodeInfoFlags to receive information about the encode operation.
The kVTEncodeInfo_Asynchronous bit may be set if the encode is (or was) running
asynchronously.
The kVTEncodeInfo_FrameDropped bit may be set if the frame was dropped (synchronously).
Pass NULL if you do not want to receive this information.
*/
VT_EXPORT OSStatus
VTCompressionSessionEncodeFrame(
CM_NONNULL VTCompressionSessionRef session,
CM_NONNULL CVImageBufferRef imageBuffer,
CMTime presentationTimeStamp,
CMTime duration, // may be kCMTimeInvalid
CM_NULLABLE CFDictionaryRef frameProperties,
void * CM_NULLABLE sourceFrameRefcon,
VTEncodeInfoFlags * CM_NULLABLE infoFlagsOut ) API_AVAILABLE(macosx(10.8), ios(8.0), tvos(10.2));
这个参数的意思是:
@param presentationTimeStamp
The presentation timestamp for this frame, to be attached to the sample buffer.Each presentation timestamp passed to a session must be greater than the previous one.
要附加到示例缓冲区的 此帧的 表示时间戳。传递给会话的每个演示时间戳必须大于上一个时间戳。
从设置的参数上来看是没有问题的,确实是大于上一个时间戳的,那么有没有可能是设置的数值间隔太大,所以导致缓冲区的内容太多,导致模糊不清,于是我将呈现时间的第二个参数改为视频的帧率,表示两个呈现时间中间只间隔一个帧率大小,而且修改为用每一个帧率大小标记一个可选关键帧,然后运行,发现拉流画面不再模糊不清,问题得以解决!
然后更新了iOS16.1.2系统以后,又出现了新的问题,竟然有大量马赛克,而且有时候只是最开始的画面是马赛克,后面画面就正常了,画面就是在不断的跳动,这又是怎么回事?于是又开始研究创建session前的设置参数,然后发现了这样一个参数值:
/*!
@constant kVTCompressionPropertyKey_AllowFrameReordering
@abstract
Enables frame reordering.
@discussion
In order to encode B frames, a video encoder must reorder frames,
which means that the order in which they will be emitted and
stored (the decode order) is different from the order in which
they were presented to the video encoder (the display order).
True by default. Set this to false to prevent frame reordering.
*/
VT_EXPORT const CFStringRef kVTCompressionPropertyKey_AllowFrameReordering API_AVAILABLE(macosx(10.8), ios(8.0), tvos(10.2)); // Read/Write, CFBoolean, Optional, defaults to true
参数值的解释是:为了对B帧进行编码,视频编码器必须对帧进行重新排序,这意味着它们将被发送和存储的顺序(解码顺序)与它们被呈现给视频编码器的顺序(显示顺序)不同。默认情况下为True。将此设置为False以防止帧重新排序。
代码中就是将此值设置为了True,可能最开始写的时候因为对帧数据进行了排序,而且不理解此值的含义,之前的iOS系统并没有那么严谨,所以设置为True并没有出现问题,现在再看参数值的注释,代码确实设置错了,而且是根据时间戳创建的帧数据,所以也不需要排序。
最终修改此数值后,马赛克的问题得以解决!!
整理不易,转载请注明,谢谢~