pyav 拆帧速度和线程数目的关系测试

前言

本次测试,关注两个点:

  • 线程数目和拆帧速度的关系
  • 不同分辨率的视频,对拆帧速度的影响

代码 demo

测试代码

import av
import time
from pathlib import Path

input_file = '/home/ponponon/Downloads/XiaoShengKeDeJiuShu_4-1080P.mp4'


def get_video_seconds(video_file_path: Path) -> int:
    import av
    with av.open(str(video_file_path), metadata_encoding='utf-8', metadata_errors='ignore') as container:
        stream = container.streams.video[0]
        return int(stream.frames/stream.average_rate)


total_seconds: int = get_video_seconds(Path(input_file))


items = []

for thread_count in reversed([1,2,3,4,5,6,7,8,9,10]):
    count = 0

    s = time.time()
    with av.open(input_file, metadata_encoding='utf-8', metadata_errors='ignore') as container:
        video_stream = container.streams.video[0]
        video_stream.thread_type = 'AUTO'
        video_stream.thread_count = thread_count

        average_fps: int = round(video_stream.average_rate)
        interval = 1

        for index, frame in enumerate(container.decode(video_stream)):

            if index % (average_fps) == 0:
                frame.to_ndarray(format='rgb24')
                count += 1
    e = time.time()

    print(f'thread count is {thread_count}, pay time is {e-s}')

    items.append([thread_count, round(e-s, 2), round(total_seconds/(e-s), 1)])

for item in items:
    print('| ', ' | '.join([str(i) for i in item]), ' |')
上面的代码,使用 pyav,按照一秒一帧的方式,从视频中提取帧

不同分辨率的视频

高分辨率视频

重新测试,加上倍速

视频是一个 1080P 的视频

╰─➤  ffmpeg -i /Volumes/SanDisk128G/标准视频/XiaoShengKeDeJiuShu_4-1080P.mp4                                         
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Volumes/SanDisk128G/标准视频/XiaoShengKeDeJiuShu_4-1080P.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf57.71.100
    description     : Packed by Bilibili XCoder v2.0.2
  Duration: 00:09:35.04, start: 0.000000, bitrate: 2832 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 2631 kb/s, 30 fps, 30 tbr, 16k tbn (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 192 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
At least one output file must be specified

平台 macbook pro Apple Silicon M1

线程数 耗时(秒) 倍速
8 12.17 47.3
7 12.52 45.9
6 13.27 43.3
5 14.48 39.7
4 16.95 33.9
3 21.58 26.6
2 28.58 20.1
1 46.3 12.4
该测试,没有做资源限制,直接跑在 macbook 上,没有使用虚拟机或者 docker 限制 cpu 或者内存资源。属于撒开丫子跑

平台 Intel(R) Xeon(R) CPU E5-2690 v4 @ 2.60GHz

线程数 耗时(秒) 倍速
10 20.98 27.4
9 20.98 27.4
8 21.5 26.7
7 21.39 26.9
6 23.82 24.1
5 24.85 23.1
4 30.03 19.1
3 37.96 15.1
2 50.08 11.5
1 74.48 7.7
该测试,没有做资源限制,直接跑在 Intel(R) Xeon(R) CPU E5-2690 v4 @ 2.60GHz 上,没有使用虚拟机或者 docker 限制 cpu 或者内存资源。属于撒开丫子跑。
Intel(R) Xeon(R) CPU E5-2690 v4 @ 2.60GHz 有 28 个物理核,56 个逻辑核,都可以被进程调用。当然,ffmpeg、pyav 不会有多少吃多少,我记得是上限最多 16 个线程。

低分辨率视频

再换一个低分辨率的视频

视频是一个 540P 的视频

╰─➤  ffmpeg -i /home/ponponon/Downloads/XiaoShengKeDeJiuShu_4-540P.mp4                         
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/ponponon/Downloads/XiaoShengKeDeJiuShu_4-540P.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf59.27.100
    description     : Packed by Bilibili XCoder v2.0.2
  Duration: 00:09:35.04, start: 0.000000, bitrate: 1049 kb/s
  Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 960x540 [SAR 1:1 DAR 16:9], 849 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
      encoder         : Lavc59.37.100 libx264
  Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 192 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
At least one output file must be specified

平台 macbook pro Apple Silicon M1

线程数 耗时(秒) 倍速
8 4.81 119.5
7 4.72 121.7
6 4.81 119.5
5 4.96 116.0
4 6.65 86.4
3 8.16 70.5
2 9.98 57.6
1 14.68 39.2

平台 Intel(R) Xeon(R) CPU E5-2690 v4 @ 2.60GHz

线程数 耗时(秒) 倍速
10 11.2 51.3
9 11.59 49.6
8 12.47 46.1
7 13.79 41.7
6 12.38 46.4
5 8.49 67.7
4 14.92 38.6
3 13.02 44.2
2 17.04 33.7
1 23.8 24.2

总结

结论一:多线程可以加速拆帧,但是不是线性相关。随着线程数的增加,倍速提升越小

结论二:分辨率越高的视频,多线程加速效果越明显

对于高分辨率的视频,8 个线程,相比 1 个线程,快了 4 倍
对于低分辨率的视频,8 个线程,相比 1 个线程,快了 2 倍

多线程会拖后腿吗?

如果机器只有一个 cpu core,此时,pyav 启用多线程拆帧,会扯后腿吗?(就是多线程比单线程还慢)

我想测试一下,所以使用 vagrant+virtualbox,限定 cpu 个数为 1

高分辨率视频

还是刚刚的 1080P 的视频

╰─➤  ffmpeg -i /Volumes/SanDisk128G/标准视频/XiaoShengKeDeJiuShu_4-1080P.mp4                                         
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Volumes/SanDisk128G/标准视频/XiaoShengKeDeJiuShu_4-1080P.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf57.71.100
    description     : Packed by Bilibili XCoder v2.0.2
  Duration: 00:09:35.04, start: 0.000000, bitrate: 2832 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 2631 kb/s, 30 fps, 30 tbr, 16k tbn (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 192 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
At least one output file must be specified

平台 Intel(R) Xeon(R) CPU E5-2690 v4 @ 2.60GHz,开一个 cpu core

线程数 耗时(秒) 倍速
10 99.71 5.8
9 95.68 6.0
8 95.02 6.1
7 92.03 6.2
6 91.68 6.3
5 88.56 6.5
4 87.9 6.5
3 85.73 6.7
2 84.11 6.8
1 75.16 7.7
测试的时候,vagrant+virtualbox,限定 cpu 个数为 1

可以看到,多线程会拖后腿,10个线程比一个线程慢了 25%!!!

低分辨率视频

视频还是选用这个

╰─➤  ffmpeg -i /home/ponponon/Downloads/XiaoShengKeDeJiuShu_4-540P.mp4                         
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/ponponon/Downloads/XiaoShengKeDeJiuShu_4-540P.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf59.27.100
    description     : Packed by Bilibili XCoder v2.0.2
  Duration: 00:09:35.04, start: 0.000000, bitrate: 1049 kb/s
  Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 960x540 [SAR 1:1 DAR 16:9], 849 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
      encoder         : Lavc59.37.100 libx264
  Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 192 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
At least one output file must be specified

平台 Intel(R) Xeon(R) CPU E5-2690 v4 @ 2.60GHz,开一个 cpu core

线程数 耗时(秒) 倍速
10 29.61 19.4
9 28.56 20.1
8 28.56 20.1
7 27.84 20.7
6 27.82 20.7
5 27.47 20.9
4 28.13 20.4
3 27.21 21.1
2 27.06 21.2
1 23.9 24.1
测试的时候,vagrant+virtualbox,限定 cpu 个数为 1

可以看到,多线程会拖后腿,10个线程比一个线程慢了 20%!!!

总结

如果你的进程跑在 k8s 或者 docker 容器中,并且使用了 cgroup 做 CPU 资源限制,那么我建议你,也要合理主动设置 pyav 的线程数

因为 pyav 默认的线程数,是按照你机器的 cpu 核来的。比如你的机器有 100 核,但是你把进程跑在 docker 容器里面,并且限制 cpu 资源上限就是一核,但是 pyav 认为我可以用 100 核,就会设置很多个线程。但实际只能最多用一核,这反而变慢了

你可能感兴趣的:(pythonffmpeg)