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

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.当然现代电脑这种情况比较少。

上图:

还是喜欢零姐啊!!!

下面是基本的实现代码

# -*- 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

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

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

到此这篇关于Pygame与OpenCV联合播放视频并保证音画同步的文章就介绍到这了,更多相关Pygame OpenCV播放视频内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python使用PyGame播放Midi和Mp3文件的方法

    本文实例讲述了python使用PyGame播放Midi和Mp3文件的方法.分享给大家供大家参考.具体实现方法如下: ''' pg_midi_sound101.py play midi music files (also mp3 files) using pygame tested with Python273/331 and pygame192 by vegaseat ''' import pygame as pg def play_music(music_file): ''' stream m

  • python使用PyGame模块播放声音的方法

    本文实例讲述了python使用PyGame模块播放声音的方法.分享给大家供大家参考.具体实现方法如下: import pygame pygame.init() pygame.mixer.music.load("sound_file.ogg") pygame.mixer.music.play() pygame.event.wait() 希望本文所述对大家的Python程序设计有所帮助.

  • Python基于pygame模块播放MP3的方法示例

    本文实例讲述了Python基于pygame模块播放MP3的方法.分享给大家供大家参考,具体如下: 安装pygame(可参考:安装Python和pygame及相应的环境变量配置) pip安装这个whl文件 装完就直接跑代码啦,很短的 import time import pygame file=r'C:\Users\chan\Desktop\Adele - All I Ask.mp3' pygame.mixer.init() print("播放音乐1") track = pygame.m

  • pygame编写音乐播放器的实现代码示例

    1.准备工作 ide:pycharm python:3.7 三方包:pygame.pyinstaller.mutagen 几首mp3格式的歌 2.开始 2.1 设计说明 1.包含 上一首.下一首.暂停/播放.快进/快退.显示当前播放的歌曲名称.显示播放进度条 2.使用pygame.mixer 3.随机播放磁盘某个目录及其子目录下的mp3文件 4.上一首.下一首用随机选择choice(list) 实现 5.进度条用按照一定速度移动进度图片来实现,过程中处理暂停.快进 6.歌曲快进播放用pygame

  • pygame播放音乐的方法

    本文实例讲述了pygame播放音乐的方法.分享给大家供大家参考.具体如下: 方法一: import pygame filename='/home/A.mp3' pygame.mixer.music.load(filename) pygame.mixer.music.play(loops=0, start=0.0) 方法二: import pygame filename='/home/pengtao/Music/b.mp3' pygame.mixer.init() pygame.mixer.mus

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

    Pygame是一个超好用的SDL绑定.自从有了Pygame,妈妈再也不用担心我内存泄漏了. 但是这里有一个问题,Pygame的Movie模块已经废弃多年,这次做课题项目却要在一个游戏中来段视频播放.有点蒙圈.Ren'py提供的解决方案是使用libav,我尝试了一早上也搞不明白pyav怎么用.后来干脆用手边的OpenCV硬读视频吧. 这里说下第三方库: pygame numpy opencv-python 其中,numpy是Anaconda自带,我没自己装过不知道,但是其他两个都是可以用pip直接

  • pygame+opencv实现读取视频帧的方法示例

    由于pygame.movie.Movie.play() 只支持MPEG格式的视频,且 pygame版本大于1.9.5好像已经不支持这个模块了,所以决定使用与opencv读取视频帧的画面,利用pygame的surface刷新窗口. 有基础的小伙伴,代码还是很好理解,直接上代码 pygame.time.Clock()同步时间 import pygame from pygame.locals import * import cv2 import sys import time FPS = 30 Fra

  • python利用opencv保存、播放视频

    代码已上传至:https://gitee.com/tqbx/python-opencv/tree/master/Getting_started_videos 目标 学习读取视频,播放视频,保存视频. 学习从相机中捕捉帧并展示. 学习cv2.VideoCapture(),cv2.VideoWriter()的使用 从相机中捕捉视频 通过自带摄像头捕捉视频,并将其转化为灰度视频显示出来. 基本步骤如下: 1.首先创建一个VideoCapture对象,它的参数包含两种: 设备索引,指定摄像机的编号. 视

  • OpenCV Matlab生成视频倒放功能

    目录 引言 1.需求分析 2.环境配置(Win11+ VS 2015 + OpenCV 2.4.9 / Matlab R2021a) 3.OpenCV实现视频倒放(C++) 3.1 输入原始视频(带声音) 3.2 原始视频转声音(mp4转mp3) 3.3 OpenCV代码 3.4 OpenCV运行结果 4.Matlab实现视频倒放 4.1 Matlab代码 4.1.1 Matlab读取视频并播放(三选一) 4.1.2 Matlab读取视频并逆转 4.2 Matlab运行结果 5.总结及应用 引言

  • OpenCV实现智能视频监控

    本文实例为大家分享了OpenCV实现智能视频监控的具体代码,供大家参考,具体内容如下 之前在做毕设的时候网上找个完整的实现代码挺麻烦的,自己做完分享一下 因为代码较为简单,没有将代码分开写在不同文件,有需要自己整合下哈 使用环境Visual Studio 2010 和 OpenCV 2.4.9 #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <ctime> usi

  • Android ViewPager中显示图片与播放视频的填坑记录

    ViewPager介绍 ViewPager的功能就是可以使视图滑动,就像Lanucher左右滑动那样. ViewPager用于实现多页面的切换效果,该类存在于Google的兼容包android-support-v4.jar里面. ViewPager: 1)ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类. 2)ViewPager类需要一个PagerAdapter适配器类给它提供数据. 3)ViewPager经常和Fragment一起使用,并且

  • Python OpenCV读取显示视频的方法示例

    目标 学习读取视频,显示视频和保存视频. 学习从相机捕捉并显示它. 你将学习以下功能:cv.VideoCapture(),cv.VideoWriter() 从相机中读取视频 通常情况下,我们必须用摄像机捕捉实时画面.提供了一个非常简单的界面.让我们从摄像头捕捉一段视频(我使用的是我笔记本电脑内置的网络摄像头) ,将其转换成灰度视频并显示出来.只是一个简单的任务开始. 要捕获视频,你需要创建一个 VideoCapture 对象.它的参数可以是设备索引或视频文件的名称.设备索引就是指定哪个摄像头的数

  • 如何实现在jupyter notebook中播放视频(不停地展示图片)

    在解决图像处理问题的时候,可以利用opencv打开视频,并一帧一帧地show出来,但是要用到imshow(),需要本地的界面支持. 代码如下 # -*- coding:utf-8*- import cv2 capture = cv2.VideoCapture("D:\\dataset\\chip_gesture.ts") # 图像处理函数 def processImg(img): # 画出一个框 cv2.rectangle(img, (500, 300), (800, 400), (0

  • 一个html5播放视频的video控件只支持android的默认格式mp4和3gp

    复制代码 代码如下: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body>

  • Android DragVideo实现播放视频时任意拖拽的方法

    Android DragVideo实现播放视频时任意拖拽 DragVideo A Method to Drag the Video When Playing Video 一种在播放视频时,能够拖拽的方案 为什么有这个工程 经常在爱奇艺网站上看电影,看到如果滑动掩盖了播放窗口后,就后在最下面有一个小播放界面.并且这个播放界面,是可以任意拖拽的.感觉很酷 既然web端能实现,就想了想在移动端设备上,是否也能实现这个效果,于是就有了- 效果图: ------> 实现思路:1.播放视频的view选择Te

随机推荐