Author: lb
ffmpeg中的OpenHEVC支持单线程,多线程解码。支持多线程解码大大提高了解码速度。其中,OpenHEVC支持三种形式的多线程解码,分别是 Frame(帧)并行解码, Slice(片)并行解码,frameSlice(帧片)并行解码。下面重点分析Frame并行解码,Slice并行解码还没有怎么研究,读懂之后再更新Slice并行解码的相关内容。
这篇文章参考了:ffmpeg多线程解码流程(http://blog.csdn.net/linpengbin/article/details/50541292) .在观看这篇文章之后可以回过头看看参考的这篇文章。
在具体分析每个并行解码方案之前,我们先大概了解一下OpenHEVC工作线程与主线程(用户线程)的结构。如图1所示:
图1: 主线程与工作线程交互结构图
Frame并行解码表示同一时间多Frame同时解码(Decode more than one frame at once). 主线程保证每次输入的数据包均为整帧数据,并将这个数据包提交给工作线程池中的某一个线程.
工作线程接收到数据包后即可进行解码,只要满足一定的条件,主线程就可以不断的把数据包提供给工作线程. 从时间上分析,主线程从码流中提取数据包耗费的时间与解码工作线程解码耗费的时间相比是较小的.因此只要我们的线程数合理的话,就能够保证线程池中的工作线程大部分时间都在解码,从而就实现了多线程的Frame并行解码,大大提高解码速度.
在分析主线程与工作线程以及工作线程与工作线程之间的交互前,我们先了解一下工作线程的几个条件状态.线程池的工作线程共有五个状态,分别是:
enum {
STATE_INPUT_READY, ///< Set when the thread is awaiting a packet.工作线程等待主线程分配数据包
STATE_SETTING_UP, ///< Set before the codec has called ff_thread_finish_setup().主线程给工作线程分配好数据包,工作线程解码
STATE_GET_BUFFER, /**<
* Set when the codec calls get_buffer().
* State is returned to STATE_SETTING_UP afterwards.
*/
STATE_GET_FORMAT, /**<
* Set when the codec calls get_format().
* State is returned to STATE_SETTING_UP afterwards.
*/
STATE_SETUP_FINISHED ///< Set after the codec has called ff_thread_finish_setup().工作线程完成解码,通知主线程可以输出
} state; //!< 初创建的线程的state为默认值STATE_INPUT_READY
代码中用枚举类型来表示这五种状态. 线程初始值均为STATE_INPUT_READY 表示工作线程处于输入状态,主线程可以给该工作线程提交数据包,供其解码.这个状态是由工作线程自己决定的,用来通知主线程.每次还没接收到数据包,或者已经完成前一帧的解码,工作线程就会将自己的状态设为STATE_INPUT_READY .
工作线程的第二个状态为 STATE_SETTING_UP, 这个状态由主线程决定.每当主线程给当前线程提交了解码数据包之后,将当前接收数据包的线程的状态更改为STATE_SETTING_UP ,状态由如下两个作用:
①:通知接收数据包的线程,数据包已经给你准备好,你可以开始解码.
②:当前接收数据包的线程,要判断前一个工作线程的状态是否处于STATE_SETTING_UP,若处于该状态,则当前线程需要等待,直到前一个工作线程状态发生改变,之后才可以接收数据包.
第三个状态只有定义了安全回调函数thread_safe_callbacks才起作用,OpenHEVC,暂时没发现有用到.
第四个状态现在没发现OpenHEVC用到.
第五个状态 STATE_SETUP_FINISHED由工作线程控制,它的作用是通知主线程,当前工作线程的解码状态已经准备好,主线程可以提交数据包给下个工作线程.
接下来,我们分析工作线程是怎么通过以上的这些状态与主线程交互,从而顺利完成帧并行解码.具体流程如下图所示:
Frame并行解码的工作线程状态转移图:
图2: 工作线程状态转移图
下面是帧(frame)并行解码的程序流程
图3:(引用自 http://blog.csdn.net/linpengbin/article/details/50541292)
现在还没具体研究代码.
frameSlice并行解码同时支持帧并行与多Slice并行.具体的解码流程可以分别参考Frame并行与Slice并行解码流程.3可以说是1和2的结合,值得我们关心的不一样的地方是工作线程池的结构.如下图所示:
图4: 线程层次关系
由上图可以看出,当frameSlice同时并行处理时,线程层次是一个树状的关系,主线程对应一个Frame多线程,而每个frame工作线程又各自对应一个Slice级别的工作线程池。