首页 » PHP教程 » phpffmpeg防壅塞技巧_FFmpeg 中的多线程解码

phpffmpeg防壅塞技巧_FFmpeg 中的多线程解码

访客 2024-11-22 0

扫一扫用手机浏览

文章目录 [+]

在任意时候,一个线程要想存取共享数据,线程必须首先得到mutex-lock,当此线程开释此共享数据的时候必须对mutex-lock解锁,在一个任意的韶光内,只有一个线程能锁定互斥锁,通过函数pthread_mutex_lock上锁,通过函数pthread_mutex_unlock解锁。

同步条件变量

条件变量用来供应另一种线程同步的方法,其基于实际的变量值来实现线程的同步操作,设置了条件变量的情形下,线程就不须要通过一直的轮询来查询条件是否知足,也不须要一直的忙等,从而能够节省很多系统资源。

phpffmpeg防壅塞技巧_FFmpeg 中的多线程解码

一个条件变量总是和一个mutex-lock对应,系统通过pthread_cond_await函数来壅塞调用的线程,一贯到条件变量得到知足。

phpffmpeg防壅塞技巧_FFmpeg 中的多线程解码
(图片来自网络侵删)

当这个线程壅塞的时候对应的mutex-lock会自动解锁,但当该线程运行的时候,其对应的mutex-lock会被加锁。

利用函数pthread_cond_signal来唤醒等待在条件变量的另一个线程,当用来唤醒多个处于壅塞状态线程时通过pthread_cond_broadcast函数来完成。

ffmpeg实现多线程方案:

Thread List,线程列表,线程列表中的每一项都映射一个解码线程。

主线程会从线程列表中按照序号由小到大(循环)提取解码线程,并把解码任务提交到该解码线程。

同时主线程在提交完解码任务后也会从线程列表中按照序号由小到大(循环)提取解码线程,并考试测验从该解码线程获取解码完成的帧。

M,主线程,紧张目的有两个:

向解码线程提交解码任务。
FFmpeg中因此packet为单位进行解码任务的提交的,按照前一小节的描述,FFmpeg便是以frame为单位进行解码任务的提交的。

从解码线程获取解码所得的帧并进行返回。
不过在第一轮进行任务提交的时候是不会去获取帧,在第一轮任务提交完成后,此时所有解码线程都已经开始进行理解码作业,那么主线程就可以开始等待第一个线程解码完成,然后考试测验去得到解码完成的帧。
这里的“考试测验”,是由于就像单线程解码时那样,并不一定是每次调用解码API都会返回一帧的。
由于h264编码的视频中常常包含B帧,这会使得码流的解码顺序并非帧的播放顺序,但是解码API必须按照帧的播放顺序进行返回,因此在进行帧的返回时会进行相应的调度。
接下来每次向一个线程提交一个解码任务后,都须要等待下一个线程空闲并考试测验返回帧。

T,解码线程,吸收解码任务并进行解码。
解码线程因此frame为单位进行处理的。
解码线程解码主线程所提交的packet,实行与单线程时一样的解码作业。

ffmpeg中的多线程解码紧张分为片 Slice级别的多线程解码 和 帧Frame级别的多线程解码:

Slice级的解码效率比Frame级的解码效率要低,故,本文先考虑Frame级的多线程解码。

干系视频推举

音视频开拓第一个项目-FFmpeg播放器开拓|FFmpeg播放器框架讲解,代码实现视频播放,如何同时解码多路视频,FFmpeg内存对齐花屏问题阐发_哔哩哔哩_bilibili

音视频学习最佳实践—从FFmpeg到流媒体做事器开拓_哔哩哔哩_bilibili

学习地址:【免费】FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高等开拓-学习视频教程-腾讯教室

须要更多ffmpeg/webrtc..音视频流媒体开拓学习资料加群812855908领取

Frame级的多线程解码

通过查看ffmpeg源码,理解到Frame级的多线程解码流程大致如下:

个中右侧的frame_worker_thread为解码线程,在open解码器时就已经创建,随后壅塞在pthread_cond_wait(&p->input_cond, &p->mutex)函数。
等待被主线程唤醒。

当主线程运行到ff_thread_decode_frame函数时,会调用submit_packet函数,这个函数的目的便是将packet包交给解码线程。

submit_packet函数会调用pthread_cond_signal(&p->input_cond)函数,这个函数便是为唤醒刚才壅塞的解码线程。

当主线程唤醒解码线程后,其pthread_cond_wait(&p->output_cond, &p->progress_mutex)函数会进入壅塞状态,等待解码线程唤醒。

如果Codec未实现update_thread_context()和线程安全的get_buffer(),则必须在解码完成后才能将状态转换为STATUS_SETUP_FINISHED,意味着下一个线程只能在当前哨程解码完成后才能开始解码。
当解码线程解码完成后,会用pthread_cond_signal(&p->output_cond)将主线程唤醒,个中会通过回调函数将解码线程解码出来的frame获取,从而输出。

2. 如果Codec实现update_thread_context()和线程安全的get_buffer(),线程状态可以在解码开始之前转换为STATUS_SETUP_FINISHED,这样,主线程就能够被唤醒,就能够去读包进行下一个包的解码,因此下一个线程就可能与当前哨程并行。

Slice级的多线程解码:

ffmpeg的slice级并行只能在帧内并行。

因此,如果在某个视频在编码时,一帧图像分为多个slice进行编码的话,那么在利用ffmpeg解码时调用slice级并行解码就会得到不错的效果。

而在实际运用中,大多数h264编码的视频都是一帧只有一个slice,对付这种视频,就算采取了slice级并行,也只有一个线程在进行解码作业。

如果一帧,即一个packet分为几个slice时,会先把这一帧前面的slice加入行列步队,到末了一个slice时统一对这一帧的所有slice进行并行解码。
个中涉及到的关键要素如下:

Slice Context List,slice的高下文是slice context(FFmpeg中的变量为slice_ctx),如果一帧中有多个slice,那么会把slice高下文组成一个列表。
前面所说的入行列步队操作会对该列表进行添补以供后续解码利用。

M,主线程,如单线程一样的流程,从用户调用解码API一贯实行到我们前面所说的入行列步队,到末了一个slice时会调用一个入口函数启动多线程解码操作。
在调用入口函数后,主线程参与的多线程解码过程一共包含三个步骤:

通过发送启动激活其它正在等待的解码线程。
在启动多线程解码后,主线程也会一同作为个中一个线程进行slice的解码。
末了等待所有线程完成任务后返回。

T,解码线程,吸收到主线程所发起的启动后,解码线程会到Slice Context List去提取个中一个slice context(原子操作),然后进行slice解码。

标签:

相关文章

介绍白点控制之路,从原理到方法

白点,作为生活中常见的现象,无处不在。对于如何控制白点,许多人却感到困惑。本文将从原理出发,探讨白点的控制方法,并结合实际案例,为...

PHP教程 2025-01-03 阅读1 评论0

介绍直播王者,如何开启你的电竞直播之旅

随着电竞产业的蓬勃发展,越来越多的年轻人投身于电竞直播行业。王者荣耀作为一款备受欢迎的MOBA手游,吸引了大量玩家和观众。如何开启...

PHP教程 2025-01-03 阅读1 评论0