如何在Python中通过FFmpeg将硬件触发相机的YUV420 Mat数据编码为HEVC视频
问题:Python中通过pypylon获取Basler相机YUV420帧,用FFmpeg NVENC编码HEVC视频
Ubuntu 20.04环境下用Python开发,通过pypylon获取Basler硬件触发相机的帧数据,需要调用GPU NVENC,用FFmpeg将YUV420格式的Mat数据编码为HEVC视频,遇到实现瓶颈。
已尝试的操作
- FFmpeg原生支持相机编码,但仅兼容网络摄像头,无法适配pypylon控制的Basler硬件触发相机
- FFmpeg转码功能不符合需求
- 尝试过JPEG序列编码,但先存帧再编码效率太低
- 已成功将相机帧通过pypylon转为HEVC适配的YUV420格式
- 了解到FFmpeg编码核心是AVFrame,推测需要将YUV420数据转为AVFrame再编码,但不清楚Python中具体实现方式
期望的简化代码逻辑
camera = pylon.InstantCamera(tlf.CreateFirstDevice()) converter = pylon.ImageFormatConverter() converter.OutputPixelFormat = pylon.PixelType_YUV420 video_handle = xxxxxx # HEVC编码句柄 while True: grabResult = camera.RetrieveResult(timeout, pylon.TimeoutHandling_ThrowException) image = converter.Convert(grabResult).GetArray() video_handle.write(frame) # 通过FFmpeg NVENC编码为HEVC视频
解决方案
1. 依赖安装
确保安装必要库及带NVENC支持的FFmpeg:
pip install ffmpeg-python opencv-python pypylon # Ubuntu下安装带NVENC的FFmpeg及NVIDIA编码库 sudo apt install ffmpeg libnvidia-encode-$(nvidia-smi | grep -oP 'Driver Version: \K[0-9]+')
2. 核心实现思路
通过ffmpeg-python库创建FFmpeg管道,直接将YUV420帧数据以字节流形式喂入NVENC编码器,跳过磁盘存储环节,保证编码效率。关键是要匹配相机输出的分辨率、帧率、像素格式与FFmpeg的输入参数。
3. 完整代码示例
import pylon import numpy as np import ffmpeg # 初始化相机及触发配置 tlf = pylon.TlFactory.GetInstance() camera = pylon.InstantCamera(tlf.CreateFirstDevice()) camera.Open() # 配置硬件触发参数(根据相机型号调整) camera.TriggerSelector.SetValue("FrameStart") camera.TriggerMode.SetValue("On") camera.TriggerSource.SetValue("Hardware") # 初始化格式转换器 converter = pylon.ImageFormatConverter() converter.OutputPixelFormat = pylon.PixelType_YUV420 # 获取相机基础参数 width = camera.Width.GetValue() height = camera.Height.GetValue() fps = camera.ResultingFrameRate.GetValue() # 构建FFmpeg NVENC编码管道 output_filename = "output.hevc" process = ( ffmpeg .input('pipe:', format='rawvideo', pix_fmt='yuv420p', s=f'{width}x{height}', r=fps) .output(output_filename, vcodec='hevc_nvenc', pix_fmt='yuv420p', preset='fast') .overwrite_output() .run_async(pipe_stdin=True) ) try: camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly) while camera.IsGrabbing(): grabResult = camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException) if grabResult.GrabSucceeded(): # 转换为YUV420格式的NumPy数组 image = converter.Convert(grabResult).GetArray() # 将数组转为字节流写入FFmpeg管道 process.stdin.write(image.tobytes()) grabResult.Release() finally: # 释放资源 camera.StopGrabbing() camera.Close() process.stdin.close() process.wait()
4. 关键说明
- FFmpeg参数解析:
format='rawvideo':指定输入为无压缩原始视频流pix_fmt='yuv420p':与pypylon输出的像素格式完全匹配vcodec='hevc_nvenc':强制使用NVIDIA硬件编码器preset='fast':可根据需求调整,ultrafast速度最快,medium质量更高
- 效率保障:直接通过内存字节流传递数据,无磁盘IO开销,适配实时编码需求
- 资源管理:必须在finally块中释放相机资源并关闭FFmpeg进程,避免内存泄漏
内容的提问来源于stack exchange,提问作者QuantumRiver
相关产品推荐
相关产品推荐

