You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将Python脚本作为systemd服务运行时生成空视频文件的问题

问题:Systemd服务运行OpenCV录屏脚本生成空损坏文件,无预览窗口

我编写了一段Python脚本,可录制指定时长的视频并显示录制画面,预期单次录制结束后由/etc/systemd/system/videoPy.service服务自动重启。脚本手动运行时正常,能弹出预览窗口并生成正常的10秒.avi文件;但通过systemd启用并启动服务后,无预览窗口,且每10秒生成的.avi文件为空且损坏。已重装opencv-python等库仍未解决,怀疑问题与cv2.VideoWriter调用有关。

附service配置

[Unit]
Description = starts video recorder
After = multi-user.target

[Service]
Type = simple
ExecStart = /usr/bin/python3 /home/fred/videoPy.py
TimeoutStartSec = infinity
Restart = on-failure
RestartSec = 5
User = fred
Group = users

[Install]
WantedBy = multi-user.target

附Python脚本

#!/usr/bin/env python3
import cv2
import numpy as np
import time

# Create a VideoCapture object. Setting to "0" opens onboard camera. Using "2" connects to usb camera.
cap = cv2.VideoCapture(0)

# Check if camera opened successfully
if (cap.isOpened() == False): 
  print("Unable to read camera feed")

# defines video length
capture_duration = 10

# Default resolutions of the frame are obtained.
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))

frame_per_sec = int('10')

# PROBLEM MAY BE BELOW. Makes an empty .avi, and that is it.
out = cv2.VideoWriter('/home/fred/videoPy_output.avi',cv2.VideoWriter_fourcc('M','J','P','G'), (frame_per_sec), (frame_width,frame_height))

# Captures video for specified amount of time
start_time = time.time()
while( int(time.time() - start_time) < capture_duration ):
ret, frame = cap.read()
if ret==True:
    #frame = cv2.flip(frame,0)
    out.write(frame)
    cv2.imshow('frame',frame)
        # Press Q on keyboard to stop recording
    if cv2.waitKey(1) & 0xFF == ord('q'):
      break
else:
    break

# When everything done, release the video capture and video write objects
cap.release()
out.release()

# Closes all the frames
cv2.destroyAllWindows()

解决方法

1. 修复图形环境与DISPLAY变量问题

systemd的multi-user.target默认不加载图形会话,OpenCV的cv2.imshow依赖图形环境,cv2.VideoWriter也可能因缺少图形上下文或DISPLAY变量未配置而异常:

  • 在service配置的[Service]段添加Environment="DISPLAY=:0";
  • 执行xhost +SI:localuser:fred(或在用户fred的~/.profile中添加该命令),赋予用户访问X服务器的权限;
  • 将service的After和WantedBy从multi-user.target改为graphical.target,确保服务在图形环境启动后再运行。

2. 调整服务重启策略

原配置Restart=on-failure仅在脚本非0码退出时重启,但脚本录制完成后会正常退出(0码),导致systemd不会重启服务。将Restart=on-failure改为Restart=always,确保脚本无论正常还是异常结束都会自动重启。

3. 完善脚本的VideoWriter检查与逻辑

  • 给VideoWriter添加初始化成功检查,避免后续写入无效:
out = cv2.VideoWriter('/home/fred/videoPy_output.avi',cv2.VideoWriter_fourcc('M','J','P','G'), frame_per_sec, (frame_width,frame_height))
if not out.isOpened():
    print("Failed to initialize VideoWriter")
    cap.release()
    exit(1)
  • 修正脚本中的缩进错误(while循环内的代码需缩进):
while( int(time.time() - start_time) < capture_duration ):
    ret, frame = cap.read()
    if ret==True:
        #frame = cv2.flip(frame,0)
        out.write(frame)
        cv2.imshow('frame',frame)
        # Press Q on keyboard to stop recording
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break
  • 避免每次重启覆盖同一个文件,可按时间戳命名输出文件,比如:
output_filename = f'/home/fred/videoPy_output_{int(time.time())}.avi'
out = cv2.VideoWriter(output_filename,cv2.VideoWriter_fourcc('M','J','P','G'), frame_per_sec, (frame_width,frame_height))

修改后的Service配置示例

[Unit]
Description=starts video recorder
After=graphical.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/fred/videoPy.py
TimeoutStartSec=infinity
Restart=always
RestartSec=5
User=fred
Group=users
Environment="DISPLAY=:0"

[Install]
WantedBy=graphical.target

内容的提问来源于stack exchange,提问作者portsample

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 10:45:40