OpenHEVC支持单进程解码,同时支持多种类型的多线程解码,具体有帧并行,Slice并行,帧片同时并行. 因此多线程初始化函数需要判断当前程序是否支持多线程,以及其类型并初始化.
//!< 判断是否并行,以及初始化
int ff_thread_init(AVCodecContext *avctx)
{
int ret = 0;
validate_thread_parameters(avctx); //!< 判断是否支持并行,以及并行的类型, 初始化线程的数量
//!< 多线程初始化
if (avctx->active_thread_type&FF_THREAD_FRAME)
ret = ff_frame_thread_init(avctx); //!< 包括frame级别初始化和Slice级别初始化(若支持)
else if (avctx->active_thread_type&FF_THREAD_SLICE)
ret = ff_slice_thread_init(avctx);//Slice级别初始化
av_log(avctx, AV_LOG_INFO, "nb threads_frame = %d, nb threads_slice %d, thread_type = %s%s \n",
avctx->thread_count_frame, avctx->thread_count,
(avctx->active_thread_type == 0 ? "null" : (avctx->active_thread_type & FF_THREAD_FRAME ? "frame" : "")),
(avctx->active_thread_type & FF_THREAD_SLICE ? "slice" : ""));
return ret;
}
函数int ff_thread_init(AVCodecContext *avctx)可分为两部分,分别是:
1. validate_thread_parameters(avctx); //!< 判断是否支持并行,以及并行的类型; 初始化线程的数量
2. //!< 多线程初始化
if (avctx->active_thread_type&FF_THREAD_FRAME)
ret = ff_frame_thread_init(avctx); //!< 包括frame级别初始化和Slice级别初始化(若支持)
else if (avctx->active_thread_type&FF_THREAD_SLICE)
ret = ff_slice_thread_init(avctx);//Slice级别线程初始化
下面先分析第一部分,函数validate_thread_parameters(avctx);这一部分的主要作用是判断是否采用多线程解码,以及多线程解码的类型,线程个数等
/**
* Set the threading algorithms used.
*
* Threading requires more than one thread.
* Frame threading requires entire frames to be passed to the codec,
* and introduces extra decoding delay, so is incompatible with low_delay.(不适合low_delay)
*
* @param avctx The context.
*/
static void validate_thread_parameters(AVCodecContext *avctx)
{ //!< 实现帧线程支持,需要在配置codec的时候设置codec的capabilities,flags,flags2
int frame_threading_supported = (avctx->codec->capabilities & CODEC_CAP_FRAME_THREADS)
&& !(avctx->flags & CODEC_FLAG_TRUNCATED)
&& !(avctx->flags & CODEC_FLAG_LOW_DELAY)
&& !(avctx->flags2 & CODEC_FLAG2_CHUNKS );
int slice_threading_supported = (avctx->codec->capabilities & CODEC_CAP_SLICE_THREADS); //!< 支持Slice级并行
//!< 支持帧级,片级并行
//!< 多线程要运行在多核机器上,才能真正发挥作用
if (avctx->thread_count == 1) { //!< 线程个数为1
avctx->active_thread_type = 0;
avctx->thread_count_frame = 1;
} else if (frame_threading_supported && (avctx->thread_type & FF_THREAD_FRAME)) { //!< 在codec初始化的时候设置avctx->thread_type |=FF_THREAD_FRAME
avctx->active_thread_type = FF_THREAD_FRAME;
avctx->thread_count_frame = avctx->thread_count;
avctx->thread_count = 1;
} else if (slice_threading_supported && (avctx->thread_type & FF_THREAD_SLICE)) {
avctx->active_thread_type = FF_THREAD_SLICE;
avctx->thread_count_frame = 1;
} else if(frameslice_threading_supported && (avctx->thread_type & FF_THREAD_FRAME_SLICE)) {
avctx->thread_count = avctx->thread_count ? avctx->thread_count : av_cpu_count()>>1;
avctx->thread_count_frame = FFMIN((av_cpu_count() / avctx->thread_count) + 1, MAX_AUTO_THREADS);
if (avctx->thread_count_frame > 1) //!< 若支持个数多于一个frame,则同时支持frame,Slice级别解码
avctx->active_thread_type = FF_THREAD_FRAME | FF_THREAD_SLICE;
else //!< 只支持Slice级别解码
avctx->active_thread_type = FF_THREAD_SLICE;
} else if (!(avctx->codec->capabilities & CODEC_CAP_AUTO_THREADS)) {
avctx->thread_count = 1;
avctx->thread_count_frame = 1;
avctx->active_thread_type = 0;
}
if (avctx->thread_count > MAX_AUTO_THREADS)
av_log(avctx, AV_LOG_WARNING,
"Application has requested %d threads. Using a thread count greater than %d is not recommended.\n",
avctx->thread_count, MAX_AUTO_THREADS);
}