如何正确终止调用ffmpeg的循环式yt-dlp Python脚本?
解决yt-dlp调用ffmpeg时无法响应Ctrl+C/优雅终止的问题
问题背景
使用Python脚本结合yt-dlp下载直播流,因格式限制yt-dlp会调用ffmpeg执行下载。为处理直播中断(如Web服务器返回403错误),脚本设置了无限循环:下载失败则等待10秒后重试,同时通过捕获KeyboardInterrupt终止脚本。
但存在以下问题:
- 本地运行时,单次按下Ctrl+C仅终止ffmpeg进程,快速按第二次会触发脚本重试;只有长按Ctrl+C才能同时终止ffmpeg和Python脚本
- 通过script-server远程启动脚本时,无法正常终止脚本
需求:让Python主脚本优先捕获中断信号,同时优雅关闭ffmpeg以避免数据丢失。
原代码片段
while LOOP: ydl_opts = { "hls_use_mpegts" : True, "hls_prefer_native" : False, "outtmpl" : f"{datetime.now():%Y%m%d_%H%M%S%z}-{EVENT_NAME}.ts", "quiet": True } try: ydl = YoutubeDL(ydl_opts) ydl.download(URLS) except utils.DownloadError: print(f"Download error, retrying in {SLEEP_FOR} seconds") time.sleep(SLEEP_FOR) except KeyboardInterrupt: LOOP = False
解决方案(适配Linux+script-server)
尝试过守护进程方法,在Windows可行但Linux环境下失效。最终通过捕获SIGTERM信号实现可靠终止,在循环前添加以下代码:
import os import signal def sigterm_handler(s, frame): global LOOP LOOP = False p = os.getpid() os.kill(p, signal.SIGINT) signal.signal(signal.SIGTERM, sigterm_handler)
原理说明
script-server会向运行中的脚本发送SIGTERM信号,自定义的信号处理器做了两件事:
- 将循环控制变量
LOOP设为False,确保脚本不会在终止后重新进入下载循环 - 向自身进程发送SIGINT信号,触发ffmpeg的优雅关闭流程,保证已录制的视频数据不会丢失
内容的提问来源于stack exchange,提问作者Eugene O.
相关产品推荐
相关产品推荐

