python-opencv
100 帧纯黑
codec |
time (s) |
size (KB) |
XVID |
0.62 |
309.97 |
MJPG |
1.15 |
1,260.75 |
mp4v |
0.61 |
288.99 |
DIVX |
0.63 |
309.97 |
h264 |
0.61 |
34.74 |
WMV1 |
0.61 |
222.48 |
WMV2 |
0.66 |
581.86 |
VP80 |
3.07 |
70.25 |
VP90 |
3.52 |
27.29 |
AVC1 |
0.62 |
34.74 |
FLV1 |
0.59 |
567.51 |
I420 |
0.36 |
300,823.94 |
WMV3 |
2.19 |
25.32 |
X264 |
0.60 |
34.79 |
YUYV |
0.37 |
300,823.94 |
IYUV |
0.36 |
300,823.94 |
YV12 |
0.37 |
300,823.94 |
YVYU |
0.37 |
300,823.94 |
UYVY |
0.37 |
300,823.94 |
M4S2 |
0.64 |
309.97 |
FMP4 |
0.62 |
309.97 |
MPEG |
1.17 |
368.08 |
100 帧纯随机
codec |
time (s) |
size (KB) |
XVID |
2.28 |
58,673.16 |
MJPG |
4.68 |
149,974.70 |
mp4v |
2.35 |
58,648.45 |
DIVX |
2.29 |
58,673.16 |
h264 |
3.76 |
50,504.66 |
WMV1 |
3.10 |
59,066.23 |
WMV2 |
3.60 |
58,994.36 |
VP80 |
129.31 |
209,960.44 |
VP90 |
266.21 |
40,090.48 |
AVC1 |
3.83 |
50,504.66 |
FLV1 |
2.71 |
58,419.96 |
I420 |
0.38 |
303,861.46 |
WMV3 |
8.54 |
39,181.57 |
X264 |
3.90 |
50,504.71 |
YUYV |
0.40 |
303,861.46 |
IYUV |
0.40 |
303,861.46 |
YV12 |
0.39 |
303,861.46 |
YVYU |
0.39 |
303,861.46 |
UYVY |
0.42 |
303,861.46 |
M4S2 |
2.38 |
58,673.16 |
FMP4 |
2.34 |
58,673.16 |
MPEG |
3.69 |
57,666.62 |
ffmpegcv
手动设置 bitrate 为 400M,不手动设置的话 gpu 编码出来的会很糊
截止本文完成时(2023.8.18),ffmpegcv 的 VideoWriter 暂不支持手动设置 bitrate(给作者提了 PR)
100 帧纯黑
codec |
time (s) |
size (KB) |
h264 |
0.65 |
9.85 |
hevc |
1.23 |
15.84 |
h264_nvenc |
0.73 |
9.85 |
hevc_nvenc |
0.70 |
15.84 |
100 帧纯随机
codec |
time (s) |
size (KB) |
h264 |
3.03 |
78,500.08 |
hevc |
16.29 |
47,981.26 |
h264_nvenc |
1.14 |
78,500.08 |
hevc_nvenc |
1.22 |
47,981.26 |
VPF (VideoProcessingFramework)
配置如下:
key |
value |
preset |
P5 |
codec |
hevc |
tuning_info |
high_quality |
fps |
60 |
s |
1920x1080 |
bitrate |
400M |
100 帧纯黑
codec |
time (s) |
size (KB) |
h264 |
0.58 |
6.83 |
hevc |
0.43 |
6.87 |
100 帧纯随机
codec |
time (s) |
size (KB) |
h264 |
1.20 |
176,795.80 |
hevc |
0.97 |
173,873.63 |
附录
测试代码
import ffmpegcv
import time
import cv2
import os
import numpy as np
res_opencv = {
("XVID", ".avi"): None,
("MJPG", ".avi"): None,
("mp4v", ".mp4"): None,
("DIVX", ".avi"): None,
("h264", ".mp4"): None,
("WMV1", ".wmv"): None,
("WMV2", ".wmv"): None,
("VP80", ".avi"): None,
("VP90", ".avi"): None,
("AVC1", ".mp4"): None,
("FLV1", ".flv"): None,
("I420", ".avi"): None,
("WMV3", ".wmv"): None,
("X264", ".mkv"): None,
("YUYV", ".avi"): None,
("IYUV", ".avi"): None,
("YV12", ".avi"): None,
("YVYU", ".avi"): None,
("UYVY", ".avi"): None,
("M4S2", ".avi"): None,
("FMP4", ".avi"): None,
("MPEG", ".avi"): None,
}
res_ffmpegcv: dict[tuple[str, str], tuple | None] = {
("h264", ".mp4"): None,
("hevc", ".mp4"): None,
("h264_nvenc", ".mp4"): None,
("hevc_nvenc", ".mp4"): None,
}
def test_opencv():
img = np.zeros((1080, 1920, 3), dtype=np.uint8)
imgs = [np.random.randint(0, 255, (1080, 1920, 3), dtype=np.uint8) for _ in range(100)]
for codec, suffix in res_opencv.keys():
fourcc = cv2.VideoWriter_fourcc(*codec)
out = cv2.VideoWriter(f'./test/test_{codec}{suffix}', fourcc, 60, (1920, 1080))
start = time.time()
for i in range(1, 100):
out.write(img)
out.release()
end = time.time()
# start = time.time()
# for img in imgs:
# out.write(img)
# out.release()
# end = time.time()
res_opencv[(codec, suffix)] = (end - start, os.stat(f'./test/test_{codec}{suffix}').st_size)
print(f"{codec}: {end - start}")
with open("./test/test.md", "w") as f:
f.write("|codec|time (s)|size (KB)|\n")
f.write("|---|---|---|\n")
for codec, suffix in res_opencv.keys():
f.write(f"|{codec}|{res_opencv[(codec, suffix)][0]:.2f}|{res_opencv[(codec, suffix)][1] / 1024:,.2f}|\n")
def test_ffmpegcv():
img = np.zeros((1080, 1920, 3), dtype=np.uint8)
imgs = [np.random.randint(0, 255, (1080, 1920, 3), dtype=np.uint8) for _ in range(100)]
for codec, suffix in res_ffmpegcv.keys():
out = ffmpegcv.VideoWriter(f'./test/test_{codec}{suffix}', codec, 60, bitrate="400M")
# start = time.time()
# for i in range(1, 100):
# out.write(img)
# out.release()
# end = time.time()
start = time.time()
for img in imgs:
out.write(img)
out.release()
end = time.time()
res_ffmpegcv[(codec, suffix)] = (end - start, os.stat(f'./test/test_{codec}{suffix}').st_size)
print(f"{codec}: {end - start}")
with open("./test/test.md", "w") as f:
f.write("|codec|time (s)|size (KB)|\n")
f.write("|---|---|---|\n")
for codec, suffix in res_ffmpegcv.keys():
f.write(
f"|{codec}|{res_ffmpegcv[(codec, suffix)][0]:.2f}|{res_ffmpegcv[(codec, suffix)][1] / 1024:,.2f}|\n")
def test_VPF():
total_num_frames = 100
uploader = PyNvCodec.PyFrameUploader(1920, 1080, PyNvCodec.PixelFormat.NV12, 0)
img = np.zeros((1080, 1920, 3), dtype=np.uint8)
img = bgr2nv12(img)
img_converted = uploader.UploadSingleFrame(img)
imgs = [np.random.randint(0, 255, (1080, 1920, 3), dtype=np.uint8) for _ in range(total_num_frames)]
start = time.time()
for i in range(len(imgs)):
img = bgr2nv12(imgs[i])
uploader.UploadSingleFrame(img)
end = time.time()
print("Convert time: ", end - start, " seconds")
out = PyNvCodec.PyNvEncoder({
"preset": "P5",
"codec": "hevc",
"tuning_info": "high_quality",
"fps": "60",
"s": "1920x1080",
"bitrate": "400M",
}, gpu_id=0)
encFile = open("./test/test.mp4", "wb")
encFrame = np.ndarray(shape=(0,), dtype=np.uint8)
framesReceived = 0
start = time.time()
# for _ in range(total_num_frames):
# success = out.EncodeSingleSurface(img_converted, encFrame, sync=False)
for img in imgs:
success = out.EncodeSingleSurface(uploader.UploadSingleFrame(img), encFrame, sync=False)
if success:
encByteArray = bytearray(encFrame)
encFile.write(encByteArray)
framesReceived += 1
while framesReceived < total_num_frames:
success = out.FlushSinglePacket(encFrame)
if success:
encByteArray = bytearray(encFrame)
encFile.write(encByteArray)
framesReceived += 1
end = time.time()
encFile.close()
print("Frames received: ", framesReceived)
print("Total time: ", end - start, " seconds")
if __name__ == "__main__":
test_opencv()
test_ffmpegcv()
Comments NOTHING