Pygame与OpenCV联合播放视频并保证音画同步

作者:h281001460 时间:2021-09-04 22:23:11 

Pygame是一个超好用的SDL绑定。自从有了Pygame,妈妈再也不用担心我内存泄漏了。

但是这里有一个问题,Pygame的Movie模块已经废弃多年,这次做课题项目却要在一个游戏中来段视频播放。有点蒙圈。Ren'py提供的解决方案是使用libav,我尝试了一早上也搞不明白pyav怎么用。后来干脆用手边的OpenCV硬读视频吧。

这里说下第三方库:

  • pygame

  • numpy

  • opencv-python

其中,numpy是Anaconda自带,我没自己装过不知道,但是其他两个都是可以用pip直接安装的。

其实Pygame使用opencv或者moviepy不少见,就是使用pygame的pygame.surfarray接口可以把numpy矩阵转化为surface,而这些视频读取库能把每帧转为numpy矩阵。这部分在下面代码中都会体现。

我测试的视频是来自ドラッグオンドラグーン(龙背上的骑兵3)的一段音游部分。音乐就是用pygame的音频模块随便播放下就好。但是注意,视频帧率必须设置为跟你的视频一致,我这里是25fps。建议稍微多设置一点,比如25.5帧是对应25帧最好的选择。因为留有余地。

平时你的游戏基本不可能莫名其妙的在逻辑中出现视频播放,所以尽量单独播放视频,防止帧数掉出25.当然现代电脑这种情况比较少。

上图:

Pygame与OpenCV联合播放视频并保证音画同步

还是喜欢零姐啊!!!

下面是基本的实现代码


# -*- coding:utf-8 -*-
import pygame
import sys
import cv2
import numpy as np
import os

if __name__ == '__main__':
   pygame.init()  # 初始化pygame
   FPS = 25.5
   #设置窗口位置
   os.environ['SDL_VIDEO_WINDOW_POS']="%d,%d" % (50,70)
   FPSClock = pygame.time.Clock()
   size = width, height = 1280, 720  # 设置窗口大小
   screen = pygame.display.set_mode(size)  # 显示窗口
   pygame.display.set_caption(u'打字游戏:反应练习')
   color = (255, 255, 255)  # 设置颜色

ogg=pygame.mixer.Sound("game.ogg")
   # pygame.mixer.music.load("")

videoCapture = cv2.VideoCapture("test.mp4")

ogg.play()

while True:
       a=pygame.time.get_ticks()

if videoCapture.isOpened():
           #从opncv读一段视频进来
           ret, frame = videoCapture.read()
           #下面这句可以获取图像大小
           # print('frame.shape:', frame.shape)
           #
           # rot90(m, k=1, axes=(0, 1)
           # m是要旋转的数组(矩阵),
           # k是旋转的次数,默认旋转1次,
           # 那是顺时针还是逆时针呢?
           # 正数表示逆时针,而k为负数时则是对数组进行顺时针方向的旋转。
           # 视频结束时会丢出一个ValueError异常
           try:
               frame = np.rot90(frame,k=-1)
           except:
               continue

frame = pygame.surfarray.make_surface(frame)

frame=pygame.transform.flip(frame,False,True)

# frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)    
           screen.blit(frame, (0,0))

# print()

for event in pygame.event.get():  # 遍历所有事件
           if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
               sys.exit()

pygame.display.flip()  # 更新全部显示
       time_next= FPSClock.tick(FPS)
       b=pygame.time.get_ticks()

pygame.quit()  # 退出pygame

好了。这样就实现了pygame播放视频~~~~

才怪呢。

因为手欠,拖动了以下窗口,然后发现,程序居然一直停留在拖动前的最后一帧,但我的音频还是在播放,当我松开鼠标的时候,视频图像才重新开始显示,这样造成视音频的同步上的问题,使鼠标松开后的视频直接跟不上音频。

尤其是这个部分是音游,一旦不同步,节奏对不上,感觉是要疯。

这问题太难受了。

于是动手解决吧……

也不难,就是时间方面的问题。掌控时间,就是掌握了全局。

于是方案如下:

方案1:通过时间和跳帧。通过计算时间【就是时间差大于某个阈值,比如100ms】发现曾经发生过停止,然后进行跳帧。因为人类手速有限,所以完全可以阈值稍微大点,防止由于cpu方面的原因造成误判。
方案2:重置音频播放,计算视频播放时间,让音频回到之前的状态。这个简单点,但是这不会太精确。需要仔细考虑使用哪个方案。
理论上跳帧方案比较好,因为帧量大,误差小。并且音频感官可以不缺失。

反复比较,选用方案一

算法如下:
设已有变量:
时间参量=下一帧-上一帧
跳帧计数器=0【在循环外】
阈值=200[时间参量大于此值说明出现故障]
跳帧系统检测到阈值超标,使用以下算法跳帧:
使用 故障值/正确延时 ,得到要跳的帧数量。然后使计数器增长到这个数量,然后跳帧。

以下是带有跳帧器的代码


# -*- coding:utf-8 -*-
import pygame
import sys
import cv2
import numpy as np
import os
# 音频同步跳帧实验
# 新增:跳帧系统

if __name__ == '__main__':
   pygame.init()  # 初始化pygame
   FPS = 25.5
   # 设置窗口位置
   os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (50, 70)
   FPSClock = pygame.time.Clock()
   size = width, height = 1280, 720  # 设置窗口大小
   # screen = pygame.display.set_mode(size,pygame.FULLSCREEN)  # 显示窗口
   screen = pygame.display.set_mode(size)  # 显示窗口
   pygame.display.set_caption(u'打字游戏:反应练习')
   color = (255, 255, 255)  # 设置颜色

ogg = pygame.mixer.Sound("game.ogg")
   # pygame.mixer.music.load("")

videoCapture = cv2.VideoCapture("test.mp4")

ogg.play()

# 真正时间
   realtime = int(1000 / FPS)

# 阈值-要稍微留下空间
   jumpyu = 100

# 跳帧计数器
   jumpnum = 0

while True:
       a = pygame.time.get_ticks()

if videoCapture.isOpened():
       #这里是跳帧工具
           if jumpnum != 0:
          #这个函数光读东西,比read少一个解码过程,所以能省点算点
               videoCapture.grab()
               jumpnum -= 1
               continue
           ret, frame = videoCapture.read()
           try:
               frame = np.rot90(frame, k=-1)
           except:
               continue

frame = pygame.surfarray.make_surface(frame)

frame = pygame.transform.flip(frame, False, True)

# frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
           screen.blit(frame, (0, 0))

# print()

for event in pygame.event.get():  # 遍历所有事件
           if event.type == pygame.QUIT:  # 如果单击关闭窗口,则退出
               sys.exit()

pygame.display.flip()  # 更新全部显示
       time_next = FPSClock.tick(FPS)
       b = pygame.time.get_ticks()
       k = b - a
#此处检测阈值,大于阈值做记录准备跳帧
       if k > jumpyu:
           print('超过阈值,跳帧')
           temp = (k - realtime)/realtime
           tempstr=str(temp)
           tempstr=tempstr[tempstr.find('.')+1:]
           if len(tempstr)>1 or tempstr[0]!='0':
               jumpnum+=(int(temp)+1)
               print('跳小数帧')
           else:
               print('跳整数帧')
               jumpnum+=int(temp)
           print('跳'+str(jumpnum)+'帧')

pygame.quit()  # 退出pygame

看看成果:为了截图拖了几下窗口,于是就已经智能跳帧了多次了。

Pygame与OpenCV联合播放视频并保证音画同步

搞定收工,这次将手贱拖动窗口造成的音画同步问题降低到最小。至少这个视频是没怎么出现节奏问题了。当然,最好的建议还是别乱拖动窗口,毕竟再精确也无法做到帧级别的完全精确。就算是全屏与窗口切换也是会有帧损失的。emm…

来源:https://blog.csdn.net/h281001460/article/details/94229007

标签:Pygame,OpenCV,播放视频
0
投稿

猜你喜欢

  • 跟老齐学Python之有容乃大的list(1)

    2021-08-17 00:27:09
  • PHP实现批量生成App各种尺寸Logo

    2023-07-23 03:59:59
  • 带进度条的ASP无组件断点续传大文件下载

    2010-06-25 18:27:00
  • PHP使用redis实现分布式锁的示例详解

    2023-06-01 16:32:19
  • Python中使用第三方库xlutils来追加写入Excel文件示例

    2022-05-23 10:04:11
  • linux下安装easy_install的方法

    2022-07-20 15:10:24
  • keras自定义损失函数并且模型加载的写法介绍

    2023-06-23 04:00:30
  • python 环境搭建 及python-3.4.4的下载和安装过程

    2022-04-24 11:40:44
  • python实现在线翻译

    2021-04-02 06:06:17
  • 浅析设计与内容呈现的关系

    2009-08-06 18:12:00
  • python向已存在的excel中新增表,不覆盖原数据的实例

    2022-04-26 15:16:51
  • asp分段插入数据库

    2010-07-02 13:13:00
  • Python时区设置方法与pytz查询时区教程

    2022-05-20 17:11:51
  • Python 如何实现变量交换

    2021-07-03 12:48:20
  • 如何使用Python实现名片管理系统

    2022-11-24 03:13:09
  • python数据处理——对pandas进行数据变频或插值实例

    2021-01-05 19:22:01
  • MySQL 表字段属性

    2011-09-10 16:01:01
  • python通过pillow识别动态验证码的示例代码

    2023-08-27 02:29:21
  • Python可变集合和不可变集合的构造方法大全

    2021-10-23 12:39:04
  • python实现比较文件内容异同

    2022-11-10 19:25:27
  • asp之家 网络编程 m.aspxhome.com