Python调用FFmpeg逐帧推流至YouTube RTMP直播无数据问题求助
解决Python+FFmpeg推流YouTube RTMP无数据接收问题
问题核心原因
你的Python实现和可正常运行的FFmpeg命令存在几个关键差异,导致YouTube无法接收有效数据流:
- 未按帧率控制发送速度:FFmpeg的
-re参数会按输入视频帧率读取数据,但你的Python代码是全速推送帧,远超正常直播帧率,YouTube服务器无法处理这种异常数据流。 - 缺失音频轨道:YouTube RTMP直播要求流必须包含音频轨道(哪怕是静音),你的代码仅推送了视频流。
- 硬编码参数不匹配:固定的
1280x720分辨率和30fps帧率如果和实际视频不符,会导致FFmpeg编码出的流格式异常。 - 缓冲区数据滞留:
stdin.write()后未及时刷新缓冲区,导致帧数据没有即时发送到FFmpeg进程。
修正后的代码
import cv2 import subprocess import time # 视频路径与RTMP地址 video_path = "video.mp4" rtmp_url = "rtmp://a.rtmp.youtube.com/live2/youtube-key" # 打开视频并获取实际参数 cap = cv2.VideoCapture(video_path) if not cap.isOpened(): print("Error: 无法打开视频文件") exit() # 获取视频真实宽高、帧率 frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = cap.get(cv2.CAP_PROP_FPS) frame_interval = 1.0 / fps # 计算每帧发送间隔 # 构建FFmpeg命令:添加静音音频、匹配视频参数、优化缓冲区 ffmpeg_command = [ 'ffmpeg', '-y', # 视频输入配置:从stdin读取rawvideo '-f', 'rawvideo', '-pixel_format', 'bgr24', '-video_size', f'{frame_width}x{frame_height}', '-framerate', str(fps), '-i', '-', # 添加静音音频:满足YouTube的音频轨道要求 '-f', 'lavfi', '-i', 'anullsrc=channel_layout=mono:sample_rate=16000', # 视频编码参数(与原命令一致) '-c:v', 'libx264', '-preset', 'veryfast', '-maxrate', '3000k', '-bufsize', '6000k', '-pix_fmt', 'yuv420p', # 音频编码参数(与原命令一致) '-c:a', 'aac', '-b:a', '128k', # 输出配置 '-f', 'flv', '-flush_packets', '1', # 强制即时输出数据包 rtmp_url ] # 启动FFmpeg进程,设置无缓冲模式 ffmpeg_process = subprocess.Popen( ffmpeg_command, stdin=subprocess.PIPE, bufsize=0 # 禁用缓冲区,确保数据即时发送 ) try: while True: ret, frame = cap.read() if not ret: break # 写入帧数据到FFmpeg ffmpeg_process.stdin.write(frame.tobytes()) # 按原视频帧率控制发送速度 time.sleep(frame_interval) finally: # 清理资源 cap.release() ffmpeg_process.stdin.close() ffmpeg_process.wait()
关键修改说明
- 动态匹配视频参数:通过
cv2.CAP_PROP_*获取视频真实的宽高和帧率,避免硬编码导致的格式不兼容。 - 添加静音音频:使用
lavfi的anullsrc生成静音音频,满足YouTube对音频轨道的强制要求。 - 帧率同步控制:通过
time.sleep(frame_interval)模拟FFmpeg-re参数的效果,让帧发送速度与原视频一致。 - 缓冲区优化:设置
bufsize=0禁用缓冲,加上-flush_packets 1强制FFmpeg即时输出数据包,避免数据滞留。
额外排查建议
- 查看FFmpeg日志:可以重定向FFmpeg的stderr输出到控制台,排查编码或推流中的错误:
ffmpeg_process = subprocess.Popen( ffmpeg_command, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, text=True, bufsize=0 ) # 可通过另一个线程读取stdout查看实时日志 - 验证RTMP密钥:确认
youtube-key是当前有效的直播密钥,无权限或过期问题。 - 检查网络:确保服务器网络可正常访问YouTube RTMP服务器,无防火墙或代理拦截。
内容的提问来源于stack exchange,提问作者YadneshD
相关产品推荐
相关产品推荐

