使用Python+OpenCV录制Twitch直播时cv2.VideoWriter报错排查
问题:Python+OpenCV录制Twitch HLS流时的写入错误处理
我想通过streamlink.streams(url)获取Twitch直播的.m3u8直链,用Python结合OpenCV实现录制。目前读取流并保存单帧图像正常,但写入视频时出错。注:我知道Streamlink和yt-dlp等工具,但只想用Python代码实现,不用CLI命令。
现有两种代码写法及对应错误:
第一种代码及错误
if streamlink.streams(url): stream = streamlink.streams(url)['best'] stream = str(stream).split(', ') stream = stream[1].strip("'") cap = cv2.VideoCapture(stream) gst_out = "appsrc ! video/x-raw, format=BGR ! queue ! nvvidconv ! omxh264enc ! h264parse ! qtmux ! filesink location=stream " out = cv2.VideoWriter(gst_out, cv2.VideoWriter_fourcc(*'mp4v'), 30, (1920, 1080)) while True: _, frame = cap.read() out.write(frame)
对应错误:
[tls @ 0x1278a74f0] Error in the pull function.
第二种代码及错误
if streamlink.streams(url): stream = streamlink.streams(url)['best'] stream = str(stream).split(', ') stream = stream[1].strip("'") while True: cap = cv2.VideoCapture(stream) _, frame = cap.read() out = cv2.VideoWriter(stream, cv2.VideoWriter_fourcc(*'mp4v'), 30, (1920, 1080)) out.write(frame)
对应错误:
OpenCV: FFMPEG: tag 0x7634706d/'mp4v' is not supported with codec id 12 and format 'hls / Apple HTTP Live Streaming'
忽略的关键点及修复方案
1. 错误的Stream URL提取方式
你通过str(stream).split(', ')提取URL的方式完全不可靠,Streamlink的Stream对象自带url属性,直接用stream.url获取即可,避免因对象字符串格式变化导致提取失败。
2. 第一种代码的GStreamer管道问题
- GStreamer管道的
filesink location未指定文件后缀,需改为location=stream.mp4,否则系统无法识别输出格式。 omxh264enc是NVIDIA硬件专用编码器,若无对应硬件支持会直接失败,建议替换为通用的x264enc(需确保OpenCV编译时包含x264支持),或者放弃GStreamer,改用OpenCV默认的FFmpeg后端。- 循环内未判断
cap.read()的返回值,当流中断时frame会为None,写入操作会触发错误,必须增加判断:ret, frame = cap.read() if not ret: break
3. 第二种代码的致命逻辑错误
- 将
cv2.VideoCapture和cv2.VideoWriter放入循环是完全错误的:每次循环都会重新打开HLS流(从头加载),并反复覆盖输出文件,根本无法实现连续录制。 cv2.VideoWriter的第一个参数需要本地文件路径或输出管道,你传入HLS流URL,FFmpeg会尝试往直播流里写入,逻辑完全错误,这也是编码格式不兼容报错的核心原因。
修复后的示例代码
import streamlink import cv2 url = "你的Twitch直播URL" streams = streamlink.streams(url) if not streams: exit("未找到可用直播流") # 正确获取流URL stream_url = streams['best'].url # 打开直播流 cap = cv2.VideoCapture(stream_url) if not cap.isOpened(): exit("无法打开直播流") # 获取流的实际参数,避免硬编码 width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = cap.get(cv2.CAP_PROP_FPS) # 若FPS获取失败, fallback到30 fps = fps if fps > 0 else 30 # 使用H264编码写入MP4(兼容性更好) fourcc = cv2.VideoWriter_fourcc(*'avc1') out = cv2.VideoWriter("output.mp4", fourcc, fps, (width, height)) if not out.isOpened(): exit("无法创建视频写入器") try: while True: ret, frame = cap.read() if not ret: print("流读取结束或出错") break out.write(frame) # 按q键可手动退出 if cv2.waitKey(1) & 0xFF == ord('q'): break finally: # 释放资源 cap.release() out.release() cv2.destroyAllWindows()
内容的提问来源于stack exchange,提问作者c0nfluks
相关产品推荐
相关产品推荐

