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

Python Socket程序中视频播放1秒后卡顿的问题排查与解决

问题分析与解决方案

核心问题

  1. 服务器端阻塞导致视频卡顿:原代码内层while True循环持续阻塞在s.accept(),完全卡住了视频帧的读取与渲染流程,视频自然无法正常播放,客户端只能拿到第一帧的1.0。
  2. 缺少OpenCV窗口事件处理:原代码没有cv2.waitKey(),即便移除Socket代码,视频窗口也会因为未处理GUI事件而无响应。
  3. 客户端单次连接限制:原客户端仅连接一次就关闭,无法持续获取更新的timestamp。

修复后的代码

服务器端(多线程分离视频与Socket服务)

import cv2
import socket
import threading

# 全局变量存储当前帧timestamp,线程锁保证读写安全
current_frame = 0.0
frame_lock = threading.Lock()

def video_player():
    global current_frame
    cap = cv2.VideoCapture("D:/video.mp4")
    if not cap.isOpened():
        print("Error opening video file")
        return
    try:
        while cap.isOpened():
            ret, frame = cap.read()
            if ret:
                cv2.imshow("Frame", frame)
                # 加锁更新当前帧timestamp
                with frame_lock:
                    current_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)
                # 控制播放帧率,40ms对应约25fps,可根据视频实际帧率调整
                if cv2.waitKey(40) & 0xFF == ord('q'):
                    break
            else:
                # 视频循环播放
                cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
                continue
    finally:
        cap.release()
        cv2.destroyAllWindows()

def socket_server():
    global current_frame
    s = socket.socket()
    port = 12345
    s.bind(('', port))
    s.listen(5)
    print(f"Socket bound to {port}, listening...")
    try:
        while True:
            # 阻塞等待客户端连接,但不影响视频线程运行
            c, addr = s.accept()
            print(f'Got connection from {addr}')
            # 加锁读取当前timestamp并发送
            with frame_lock:
                frame_data = str(current_frame).encode("utf-8")
            c.sendall(frame_data)
            c.close()
    except Exception as e:
        print(f"Socket error: {e}")
    finally:
        s.close()

if __name__ == "__main__":
    # 启动两个独立线程
    video_thread = threading.Thread(target=video_player)
    server_thread = threading.Thread(target=socket_server)
    video_thread.start()
    server_thread.start()
    video_thread.join()
    server_thread.join()

客户端(持续获取timestamp版本)

import socket
import time

s = socket.socket()
port = 12345

try:
    s.connect(('localhost', port))
    print("Connected to server")
    # 持续拉取最新timestamp,间隔可自定义
    while True:
        data = s.recv(32).decode().strip()
        if data:
            print(f"Current video frame: {data}")
        time.sleep(1)
except Exception as e:
    print(f"Client error: {e}")
finally:
    s.close()

关键修改说明

  • 多线程分离:将视频播放与Socket服务拆分为两个独立线程,避免互相阻塞,保证视频流畅播放的同时响应客户端请求。
  • 线程安全控制:用threading.Lock()保护全局变量current_frame,避免多线程读写冲突。
  • OpenCV事件处理:加入cv2.waitKey()处理窗口事件,解决视频窗口无响应问题,同时支持按q退出播放。
  • 客户端持续请求:修改为循环接收逻辑,可实时获取视频最新的timestamp。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 16:45:53