ffmpeg解码多线程项目总结

来源:互联网 发布:a站和b站区别知乎 编辑:程序博客网 时间:2024/06/03 21:17

转自:http://blog.csdn.net/shuiniu1224/article/details/24932869

从3月份开始到4月底,开始了多线程解码的项目。这个项目主要为了利用当今的CPU多核技术,将H.264解码单线程变成多线程,以提高解码速度。刚开始的时候不知道如何下手,不过老大(项目经理)给了我一些提示,让我先看看ffmpeg中的解码多线程是如何实现的,然后再根据ffmpeg中的多线程思路来完善我们公司自己的解码器多线程功能。因此,基于这个项目基本上是按照以下的步骤实现的:

1)由于按照老大的提示需要参照ffmpeg的多线程解码思路,所以第一步首先就需要实现ffmpeg的单步调试,以理解ffmpeg多线程解码的运行方式。这里可选择两种方法,第一种适合只安装了VS2010的windows用户,第二种则适合于在linux上进行代码调试的人。第一种方法稍微复杂,主要是利用编译出的pdb信息进行调试,详细步骤可参考之前的文章《VS2010中进行ffmpeg编译与单步调试》。第二种方法则相对比较简单,由于ffmpeg源码本身是在linux平台上进行开发的,因此只要在linux平台上先编译源码,然后安装相应的IDE进行调试即可,IDE可采用QT creator或者code blocks。不过这里值得注意的是,利用第一种方法进行ffmpeg的调试相对比较粗糙,因为现在最新的ffmpeg版本代码都需要C99的支持,而VS2010则不支持C99标准,所以需要在编译时下载C99 warper进行包装后才能编译通过形成pdb文件,但这样一来,在调试的时候问题也就来了,由于在编译的时候采用了C99转换,故而实际生成的调试信息和源代码不能精确匹配,可能会给调试人员带来理解上的困扰。因而,笔者建议,在条件允许的情况下,可以采用VS2012以后的版本进行调试,或者最好采用linux平台进行代码调试。但如果你没有安装linux平台怎么办呢?笔者按照自己的经验,建议你可以安装一台虚拟机,然后在虚拟机上装一个linux系统,这样你就能够充分享用windows和linux两者带来的便利了。

2)ffmpeg的调试工作做好以后,接下来就是理解ffmpeg的多线程解码思路了。通过调试我们可以发现,在ffmpeg中,可以分别采用帧内多线程解码和帧间多线程解码,帧内多线程解码的的依据主要是帧内各宏块的参考宏块可能相同,需要相同参考宏块进行解码的宏块可以同时进行解码。同理,帧间多线程解码的依据也是由于各帧图像需要的参考帧可能相同,需要相同参考帧的帧可以同时进行解码,最容易理解的就是部分B帧的并行解码了。由于帧内多线程解码的效率并不是很高,因此我主要针对的是帧间多线程解码方法,关于帧间多线程解码的内容可以参考网站http://blog.csdn.net/bsplover/article/details/7542980和硕士论文《视频编解码算法的并行研究》,以及以下三张图片内容:



相信通过这三个资料的学习,再结合相应的代码跟踪调试,应该对于理解ffmpeg帧间多线程解码思路不会太难。

3)理解了ffmpeg多线程解码,接下里就是对应公司的H.264解码器进行修改了。在进行这一步骤之前,需要先熟悉多线程编码的相关问题。关于多线程编码,在操作系统进入多任务作业时就已经成为了大家研究的热点。随后,在硬件CPU多核的推动之下,越来越多的系统和应用程序采用了多线程实现的方式,这样可以充分利用CPU多核技术,使任务得以并行处理,加快了任务处理的时间,提高了程序运行的效率。在不同的平台下,也出现了不同的多线程编码方式,如在windows下,以win32多线程编码为主,在linux平台上,则采用基于POSIX标准的pthread进行多线程编码,两种平台上的编码底层接口不同,也导致了跨平台移植的困难。所幸,之后出现了win32 pthread版本的接口,可以方便在windows平台下开发出符合POSIX标准的linux上可运行的多线程代码。关于win32 pthread的源码,大家可以上http://www.sourceware.org/pthreads-win32/上下载,这样你就可以在vs平台上使用win32 源码或者DLL嵌入进行调试编码。

接下来要讲一下多线程编码常用的一些函数了,这里分为win32 和POSIX进行对比说明:

1.关于线程创建和消亡的操作。

1.1 创建和撤销一个POSIX线程

pthread_create(&tid, NULL, start_fn, arg);

pthread_exit(status);

1.2 创建和撤销一个Win32线程

CreateThread(NULL, NULL, start_fn, arg, NULL, NULL);

ExitThread(status);

2.关于线程的等待(join or wait for)的操作。

在多线程模型下,一个线程有可能必须等待其他的线程结束了才能继续运行。比如说司机和售票员,司机只有当售票员确定所有的人都上车了,即售票员的行动结束以后才能开车,在这之前司机必须等待。

2.1等待一个POSIX线程

pthread_join(T1);

2.2等待一个Win32线程

WaitForSingleObject(T1);

Win32还提供一个调用WaitForMulitpleObject(T[]),可以用来等待多个线程。

3.关于线程的强制撤销(cancellation or killing)的操作。

3.1 撤销一个POSIX线程

pthread_cancel(T1);

3.2 撤销一个Win32线程

TerminateThread(T1);

4.线程的同步机制(synchronization)

4.1互斥量mutex是最简单的同步变量,它实现的操作实际上就是一把互斥锁,如果一个线程拥有了这个mutex,其他线程在申请拥有这个mutex的时候,就会被阻塞,直到等到先那个线程释放这个mutex。在任何时候,mutex至多只有一个拥有者,它的操作是完全排他性的。

4.1.1 POSIX的mutex操作

pthread_mutex_init(MUTEX, NULL);

pthread_mutex_lock(MUTEX);

pthread_mutex_trylock(MUTEX);

pthread_mutex_timedlock(MUTEX, ABSTIME);

pthread_mutex_unlock(MUTEX);

pthread_mutex_destroy(MUTEX);

4.1.2 Win32的mutex操作

CreateMutex(NULL, FALSE, NULL);

WaitForSingleObject(MUTEX);

ReleaseMutex(MUTEX);

CloseHandle(MUTEX);

4.1.3 Win32的CriticalSection操作

InitializeCriticalSection(&cs);

EnterCriticalSection(&cs);

TryEnterCriticalSection(&cs);

LeaveCriticalSection(&cs);

DeleteCriticalSection(&cs);


4.2信号量semaphore最初是由E.W.Dijkstra于20世纪60年代引入的。通常,信号量是一个计数器和对于这个计数器的两个操作(分别称之为P,V操作),以及一个等待队列的总和。一个P操作使得计数器减少一次,如果计数器大于零,则执行P操作的线程继续执行,如果小于零,那么该线程就会被放入到等待队列中;一个V操作使得计数器增加一次,如果等待队列中由等待的线程,便释放一个线程。

4.2.1 POSIX的信号量操作

sem_init(SEM, 0, VALUE);

sem_wait(SEM);

sem_trywait(SEM);

sem_destroy(SEM);

4.2.2 Win32的信号量操作

CreateSemaphore(NULL, 0, MaxVal, NULL);

WaitForSingleObject(SEM);

ReleaseSemaphore(SEM);

CloseHandle(SEM);

4.3条件量condition variables是一种非常类似于信号量的同步变量,不同的是,信号量关注的是counter的计数是多少,而条件量关注的仅仅是条件是否满足,换一句话说,条件量可以简单看作是计数器最大取值不超过1的信号量,但在它绝对不是信号量的简单实现,某些情况下,它比信号量更直观。

4.3.1 POSIX的条件量的操作

phtread_cond_init(COND, NULL);

phtread_cond_wait(COND, MUTEX);

phtread_cond_timedwait(COND, MUTEX, TIME);

phtread_cond_signal(COND);

phtread_cond_broadcast(COND);

phtread_cond_destroy(COND);

其中broadcast是用来唤醒所有等在该条件量上的线程。

Win32中并没有条件量这个概念,但是它实现了一种叫做Event的同步变量,实质上和条件量是差不多的。


学习完上面的这些常用的多线程接口函数之后,我想大家现在就可以自己编写一个多线程的程序了,当然为了支持跨平台,你可以选用上面提到的win32 pthread。同样,我也是根据以上的多线程编码知识实现了多线程解码项目,最后欢迎大家提出批评和讨论意见~~

0 0