如何在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




