[ffmpeg] h264并行解码_玖富娱乐主管发布


玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。

ffmpeg中的并行解码分为两种:

  • Frame-level Parallelism
  • Slice-level Parallelism

 

Frame-level Parallelism

帧间依靠

我们之前议论过Frame-level Parallelism。在之前的文章中,我们说过在举行帧级的并行处置惩罚时,因为I、P帧是作为参考帧(B帧也能作为参考帧),因而不能对其举行并行处置惩罚,只需非参考B帧才是最相宜举行并行处置惩罚的帧。不外实在若是我们能正确地处置惩罚好各个帧之间的依靠干系,无论是I、P照样B帧都能举行并行处置惩罚。FFmpeg为了到达这一目标,对我们之前所议论的Frame-level Parallelism举行了革新:增加帧间依靠。

h264的帧间依靠重要有两个:

  • 举行活动赔偿时须要参考帧供应参考地区的像素数据。在解码一个宏块的历程傍边,取得宏块中每一个分块的活动向量与参考帧后,就可以肯定宏块的各个分块的参考地区,然后就可以够从这些地区提取像素数据举行活动赔偿。
  • 编码形式为B Direct的宏块在盘算活动向量时,须要位于第一个后向参考帧的co-located块的活动向量,用来盘算出以后帧的前向和后向活动向量。

FFmpeg关于上述依靠的解决计划是:

  • 关于每一个分块,在举行活动赔偿之前,守候该分块所依靠的参考地区的末了一行(以像素为单元,透露表现这一行的值row是相对整幅图象来讲的,下同)的停当音讯[1]
  • 关于编码形式为B Direct的宏块,在盘算活动向量之前,守候co-located块的第一行的停当音讯(因为我们只须要该co-located块的活动向量,既然第一行像素已停当,那末活动向量肯定是已停当了)[2]
  • 解码器每解码完成一行宏块,就关照发送该宏块的末了一行的停当音讯(若是以后视频指定了deblocking,因为以后行宏块的deblocking须要用到下一行宏块的上方4行像素,因而停当的row值须要举行响应的调解)[3]

 

Packet与Frame

在议论FFmpeg的完成之前,我们须要先相识packet(AVPacket)与frame(AVFrame)之间的干系。分歧的编码花样或许会有所分歧,不外h264在FFmpeg中的一个packet中所包罗的数据就是一个frame(一帧)。一样平常状况下一帧就是一个slice,如许的话一个packet中只需一个slice;固然,一帧也有可能会分为多个slice,若是是这类状况的话,一个packet中会包罗这一帧一切的slice。

我们之所以在这里议论这两者之间的干系,是因为FFmpeg每次都是以一个packet为单元向解码器传入须要解码的数据,也就是说每次会向h264解码器传入一帧的数据。

 

完成计划[4]

FFmpeg完成计划以下:

Thread List,线程列表,线程列表中的每一项都映照一个解码线程。主线程会从线程列表中依照序号由小到大(轮回)提取解码线程,并把解码义务提交到该解码线程。同时主线程在提交完解码义务后也会从线程列表中依照序号由小到大(轮回)提取解码线程,并实验从该解码线程猎取解码完成的帧。

M,主线程,重要目标有两个:

  • 向解码线程提交解码义务。FFmpeg中是以packet为单元举行解码义务的提交的,依照前一小节的形貌,FFmpeg就是以frame为单元举行解码义务的提交的。
  • 从解码线程猎取解码所得的帧并举行返回。不外在第一轮举行义务提交的时刻是不会去猎取帧,在第一轮义务提交完成后,此时一切解码线程都已最先举行相识码功课,那末主线程就可以够最先守候第一个线程解码完成,然后实验去取得解码完成的帧(这里的“实验”,是因为就像单线程解码时那样,并不一定是每次挪用解码API都邑返回一帧的。因为h264编码的视频中经常包罗B帧,这会使得码流的解码递次并不是帧的播放递次,然则解码API必需依照帧的播放递次举行返回,因而在举行帧的返回时会举行响应的调解)。接下来每次向一个线程提交一个解码义务后,都须要守候下一个线程余暇并实验返回帧。

T,解码线程,吸收解码义务并举行解码。解码线程是以frame为单元举行处置惩罚的。解码线程解码主线程所提交的packet,实行与单线程时一样的解码功课,固然在解码功课时期会遇到我们上面所述的帧间依靠并举行处置惩罚。

 

隐式的帧间依靠

帧间依靠除上面所述的显着存在的帧间依靠以外,另有一处较为隐藏的帧间依靠。

解码所需的参考图象列表依靠于POC,而在盘算图象POC时,须要对相邻两个frame(或许说slice)头部的pic_order_cnt_lsb或许frame_num举行对照。这就注解在最先一个frame的解码之前,须要把上一个frame的这些参数传入以后frame。有了上一个frame头部的这些参数,以后的frame就可以依照单线程解码那样正确地盘算出以后frame的POC。

FFmpeg把这参数传入操纵完成在了ff_h264_update_thread_context傍边,该函数会在提交解码义务前被挪用[5]

 

 

Slice-level Parallelism

如我们之前议论过的Slice-level Parallelism,ffmpeg的slice级并行只能在帧内并行。因而,若是在某个视频在编码时,一帧图象分为多个slice举行编码的话,那末在运用ffmpeg解码时挪用slice级并行解码就会取得不错的结果。而在现实运用中,大多数h264编码的视频都是一帧只需一个slice,关于这类视频,就算采用了slice级并行,也只需一个线程在举行解码功课。

-玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。-

 

完成计划

若是一帧,即一个packet分为几个slice时,会先把这一帧前面的slice到场行列,到末了一个slice时一致对这一帧的一切slice举行并行解码[6]。个中涉及到的症结要素以下:

Slice Context List,slice的上下文是slice context(FFmpeg中的变量为slice_ctx),若是一帧中有多个slice,那末会把slice上下文构成一个列表。前面所说的入行列操纵会对该列表举行添补以供后续解码运用。

M,主线程,如单线程一样的流程,从用户挪用解码API一向实行到我们前面所说的入行列,到末了一个slice时会挪用一个进口函数启动多线程解码操纵。在挪用进口函数后,主线程介入的多线程解码历程一共包罗三个步调[7]

  1. 经由过程发送启动音讯激活别的正在守候的解码线程。
  2. 在启动多线程解码后,主线程也会一同作为个中一个线程举行slice的解码。
  3. 末了守候一切线程完成义务后返回。

T,解码线程,吸收到主线程所提议的启动音讯后,解码线程会到Slice Context List去提取个中一个slice context(原子操纵),然后举行slice解码[8]

 

※在举行slice并行解码时deblocking是没法逾越slice界限的,若是视频指定了逾越界限的deblocking,那末deblocking须要要留到一切slice解码完成后再做。与此同时,若是指定ffmpeg举行疾速解码,也会在解码线程内举行deblocking,不外此时的deblocking就是对底本举行逾越界限的deblocking举行了非逾越界限的deblocking,会影响视频图象质量[9]

 

Example

ffmpeg只需在打开解码器之前举行以下设置就可以够实行并行解码。

    avcodec_alloc_context3(NULL);
    avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[Stream]->codecpar);
    Codec = avcodec_find_decoder(pCodecCtx->codec_id);

    pCodecCtx->thread_count = 4;
    pCodecCtx->thread_type = FF_THREAD_FRAME;
    //pCodecCtx->thread_type = FF_THREAD_SLICE;

    avcodec_open2(pCodecCtx, pCodec, NULL);

两行离别为:

设置并行解码数量,即解码线程数。

设置并行解码范例为FF_THREAD_FRAME或许FF_THREAD_SLICE,离别对应Frame-level Parallelism和Slice-level Parallelism。

 

Reference:

1. await_references

2. await_reference_mb_row

3. decode_finish_row

4. ff_thread_decode_frame

5. submit_packet

6. decode_nal_units

7. avpriv_slicethread_execute

8. thread_worker, run_jobs, worker

9. h264_slice_init

-玖富娱乐是一家为代理招商,直属主管信息发布为主的资讯网站,同时也兼顾玖富娱乐代理注册登录地址。