You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Python 3.6中通过ffpyplayer在Pygame窗口显示视频?

解决Pygame中用ffpyplayer播放MP4音画同步的问题

嘿,我太懂你这情况了——之前用cv2只能出画面没声音,换ffpyplayer又反过来只有声音没画面,这折腾人的!你说代码能读到帧但显示不出来,核心问题就是ffpyplayer输出的帧格式和Pygame的Surface不兼容,得做格式转换,还得补上Pygame窗口刷新和事件循环的步骤,不然画面根本出不来。

下面是修正后的完整代码,我把关键步骤都标出来了:

import pygame
from ffpyplayer.player import MediaPlayer
import numpy as np

def playVid(filename):
    # 初始化Pygame(如果全局没初始化过的话)
    pygame.init()
    
    # 打开视频文件和媒体播放器
    player = MediaPlayer(filename)
    video_frame, val = player.get_frame()
    
    # 获取视频分辨率,创建对应大小的Pygame窗口
    if val != 'eof' and video_frame is not None:
        # ffpyplayer返回的帧是(h, w, 3)的numpy数组
        h, w = video_frame[0].shape[:2]
        screen = pygame.display.set_mode((w, h))
    else:
        print("无法读取视频帧,请检查文件路径是否正确")
        return
    
    clock = pygame.time.Clock()
    running = True
    
    while running:
        # 必须处理Pygame事件!不然窗口会直接卡死
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            # 加个按ESC跳过视频的逻辑,方便玩家操作
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    running = False
        
        # 获取下一帧和状态(val='eof'表示视频结束)
        video_frame, val = player.get_frame()
        
        if val == 'eof':
            running = False
            break
        
        if video_frame is not None:
            # 关键步骤1:把ffpyplayer的BGR格式帧转成Pygame需要的RGB
            frame_bgr = video_frame[0]
            frame_rgb = frame_bgr[:, :, ::-1]  # 用numpy切片反转颜色通道
            # 关键步骤2:把numpy数组转换成Pygame Surface(交换轴适配Pygame的宽高顺序)
            surf = pygame.surfarray.make_surface(frame_rgb.swapaxes(0, 1))
            # 将帧绘制到窗口上
            screen.blit(surf, (0, 0))
            # 刷新窗口显示,这一步千万别忘!
            pygame.display.flip()
        
        # 控制帧率,保证画面和音频同步(可根据视频实际帧率调整数值)
        clock.tick(30)
    
    # 播放结束后释放资源
    player.close()
    pygame.quit()

# 调用示例,替换成你的过场动画路径
playVid("cutscene.mp4")

重点说明:

  • 帧格式转换:ffpyplayer返回的帧是BGR格式的numpy数组,而Pygame只认RGB,所以用[:, :, ::-1]反转颜色通道;另外numpy数组的维度是(高, 宽, 通道),Pygame需要(宽, 高, 通道),所以用swapaxes(0,1)交换轴。
  • 事件循环:必须处理Pygame的事件,不然窗口会无响应,同时加入按键退出逻辑更符合游戏需求。
  • 资源释放:播放结束后记得关闭播放器和Pygame,避免内存泄漏。

如果遇到音画不同步的问题,可以调整clock.tick()的数值(比如改成视频实际帧率24/30/60),或者用ffpyplayer的get_pts()方法获取帧时间戳做更精确的同步。

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

火山引擎 最新活动