Python实现的视频播放器功能完整示例


Posted in Python onFebruary 01, 2018

本文实例讲述了Python实现的视频播放器功能。分享给大家供大家参考,具体如下:

# -*- coding:utf-8 -*-
#! python3
# ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions 
# are met:
#
# * Redistributions of source code must retain the above copyright
#  notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright 
#  notice, this list of conditions and the following disclaimer in
#  the documentation and/or other materials provided with the
#  distribution.
# * Neither the name of pyglet nor the names of its
#  contributors may be used to endorse or promote products
#  derived from this software without specific prior written
#  permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------
'''Audio and video player with simple GUI controls.
'''
__docformat__ = 'restructuredtext'
__version__ = '$Id: $'
import sys
from pyglet.gl import *
import pyglet
from pyglet.window import key
def draw_rect(x, y, width, height):
  glBegin(GL_LINE_LOOP)
  glVertex2f(x, y)
  glVertex2f(x + width, y)
  glVertex2f(x + width, y + height)
  glVertex2f(x, y + height)
  glEnd()
class Control(pyglet.event.EventDispatcher):
  x = y = 0
  width = height = 10
  def __init__(self, parent):
    super(Control, self).__init__()
    self.parent = parent
  def hit_test(self, x, y):#点中控件
    return (self.x < x < self.x + self.width and 
        self.y < y < self.y + self.height)
  def capture_events(self):
    self.parent.push_handlers(self)
  def release_events(self):
    self.parent.remove_handlers(self)
class Button(Control):
  charged = False
  def draw(self):
    if self.charged:
      glColor3f(0, 1, 0)
    draw_rect(self.x, self.y, self.width, self.height)
    glColor3f(1, 1, 1)
    self.draw_label()
  def on_mouse_press(self, x, y, button, modifiers):
    self.capture_events()
    self.charged = True
  def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
    self.charged = self.hit_test(x, y)
  def on_mouse_release(self, x, y, button, modifiers):
    self.release_events()
    if self.hit_test(x, y):
      self.dispatch_event('on_press')
    self.charged = False
Button.register_event_type('on_press')#注册事件
class TextButton(Button):
  def __init__(self, *args, **kwargs):
    super(TextButton, self).__init__(*args, **kwargs)
    self._text = pyglet.text.Label('', anchor_x='center', anchor_y='center')
  def draw_label(self):
    self._text.x = self.x + self.width / 2
    self._text.y = self.y + self.height / 2
    self._text.draw()
  def set_text(self, text):
    self._text.text = text
  text = property(lambda self: self._text.text,
          set_text)
class Slider(Control):
  THUMB_WIDTH = 6
  THUMB_HEIGHT = 10
  GROOVE_HEIGHT = 2
  def draw(self):
    center_y = self.y + self.height / 2
    draw_rect(self.x, center_y - self.GROOVE_HEIGHT / 2, 
         self.width, self.GROOVE_HEIGHT)
    pos = self.x + self.value * self.width / (self.max - self.min)
    draw_rect(pos - self.THUMB_WIDTH / 2, center_y - self.THUMB_HEIGHT / 2, 
         self.THUMB_WIDTH, self.THUMB_HEIGHT)
  def coordinate_to_value(self, x):#改变进度
    return float(x - self.x) / self.width * (self.max - self.min) + self.min
  def on_mouse_press(self, x, y, button, modifiers):
    value = self.coordinate_to_value(x)
    self.capture_events()
    self.dispatch_event('on_begin_scroll')
    self.dispatch_event('on_change', value)
  def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
    value = min(max(self.coordinate_to_value(x), self.min), self.max)
    self.dispatch_event('on_change', value)
  def on_mouse_release(self, x, y, button, modifiers):
    self.release_events()
    self.dispatch_event('on_end_scroll')
Slider.register_event_type('on_begin_scroll')
Slider.register_event_type('on_end_scroll')
Slider.register_event_type('on_change')
class PlayerWindow(pyglet.window.Window):
  GUI_WIDTH = 400
  GUI_HEIGHT = 40
  GUI_PADDING = 4#按钮间隔
  GUI_BUTTON_HEIGHT = 16
  def __init__(self, player):
    super(PlayerWindow, self).__init__(caption='Media Player',
                      visible=False, 
                      resizable=True)
    self.player = player
    self.player.push_handlers(self)
    self.player.eos_action = self.player.EOS_PAUSE
    self.slider = Slider(self)
    self.slider.x = self.GUI_PADDING#类变量
    self.slider.y = self.GUI_PADDING * 2 + self.GUI_BUTTON_HEIGHT
    self.slider.on_begin_scroll = lambda: player.pause()
    self.slider.on_end_scroll = lambda: player.play()
    self.slider.on_change = lambda value: player.seek(value)
    self.play_pause_button = TextButton(self)
    self.play_pause_button.x = self.GUI_PADDING
    self.play_pause_button.y = self.GUI_PADDING
    self.play_pause_button.height = self.GUI_BUTTON_HEIGHT
    self.play_pause_button.width = 45
    self.play_pause_button.on_press = self.on_play_pause
    win = self#自有妙用
    self.window_button = TextButton(self)
    self.window_button.x = self.play_pause_button.x + \
                self.play_pause_button.width + self.GUI_PADDING
    self.window_button.y = self.GUI_PADDING
    self.window_button.height = self.GUI_BUTTON_HEIGHT
    self.window_button.width = 90
    self.window_button.text = 'Windowed'
    self.window_button.on_press = lambda: win.set_fullscreen(False)#注意不能写self
    self.controls = [
      self.slider, 
      self.play_pause_button,
      self.window_button,
    ]
    x = self.window_button.x + self.window_button.width + self.GUI_PADDING
    i = 0
    for screen in self.display.get_screens():
      screen_button = TextButton(self)
      screen_button.x = x
      screen_button.y = self.GUI_PADDING
      screen_button.height = self.GUI_BUTTON_HEIGHT
      screen_button.width = 80
      screen_button.text = 'Screen %d' % (i + 1)
      screen_button.on_press = \
        (lambda s: lambda: win.set_fullscreen(True, screen=s))(screen)
      self.controls.append(screen_button)
      i += 1
      x += screen_button.width + self.GUI_PADDING
  def on_eos(self):
    self.gui_update_state()
  def gui_update_source(self):
    if self.player.source:
      source = self.player.source
      self.slider.min = 0.
      self.slider.max = source.duration
    self.gui_update_state()
  def gui_update_state(self):
    if self.player.playing:
      self.play_pause_button.text = 'Pause'
    else:
      self.play_pause_button.text = 'Play'
  def get_video_size(self):
    if not self.player.source or not self.player.source.video_format:
      return 0, 0
    video_format = self.player.source.video_format
    width = video_format.width
    height = video_format.height
    if video_format.sample_aspect > 1:
      width *= video_format.sample_aspect
    elif video_format.sample_aspect < 1:
      height /= video_format.sample_aspect
    return width, height
  def set_default_video_size(self):
    '''Make the window size just big enough to show the current
    video and the GUI.'''
    width = self.GUI_WIDTH
    height = self.GUI_HEIGHT
    video_width, video_height = self.get_video_size()
    width = max(width, video_width)
    height += video_height
    self.set_size(int(width), int(height))
  def on_resize(self, width, height):
    '''Position and size video image.'''
    super(PlayerWindow, self).on_resize(width, height)
    self.slider.width = width - self.GUI_PADDING * 2
    height -= self.GUI_HEIGHT
    if height <= 0:
      return
    video_width, video_height = self.get_video_size()
    if video_width == 0 or video_height == 0:
      return
    display_aspect = width / float(height)
    video_aspect = video_width / float(video_height)
    if video_aspect > display_aspect:
      self.video_width = width
      self.video_height = width / video_aspect
    else:
      self.video_height = height
      self.video_width = height * video_aspect
    self.video_x = (width - self.video_width) / 2
    self.video_y = (height - self.video_height) / 2 + self.GUI_HEIGHT
  def on_mouse_press(self, x, y, button, modifiers):
    for control in self.controls:
      if control.hit_test(x, y):
        control.on_mouse_press(x, y, button, modifiers)
  def on_key_press(self, symbol, modifiers):
    if symbol == key.SPACE:
      self.on_play_pause()
    elif symbol == key.ESCAPE:
      self.dispatch_event('on_close')
  def on_close(self):
    self.player.pause()
    self.close()
  def on_play_pause(self):
    if self.player.playing:
      self.player.pause()
    else:
      if self.player.time >= self.player.source.duration:#如果放完了
        self.player.seek(0)
      self.player.play()
    self.gui_update_state()
  def on_draw(self):
    self.clear()
    # Video
    if self.player.source and self.player.source.video_format:
      self.player.get_texture().blit(self.video_x,
                      self.video_y,
                      width=self.video_width,
                      height=self.video_height)
    # GUI
    self.slider.value = self.player.time
    for control in self.controls:
      control.draw()
if __name__ == '__main__':
  if len(sys.argv) < 2:
    print('Usage: media_player.py <filename> [<filename> ...]')
    sys.exit(1)
  for filename in sys.argv[1:]:
    player = pyglet.media.Player()
    window = PlayerWindow(player)
    source = pyglet.media.load(filename)
    player.queue(source)
    window.gui_update_source()
    window.set_default_video_size()
    window.set_size(400,400)
    window.set_visible(True)
    window.gui_update_state()
    player.play()
  pyglet.app.run()

注:这里用到的pyglet库,可点击此处下载https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyglet

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
python 提取文件的小程序
Jul 29 Python
python访问sqlserver示例
Feb 10 Python
Python 序列化 pickle/cPickle模块使用介绍
Nov 30 Python
Python的randrange()方法使用教程
May 15 Python
学习python之编写简单乘法口诀表实现代码
Feb 27 Python
关于Python面向对象编程的知识点总结
Feb 14 Python
python中利用xml.dom模块解析xml的方法教程
May 24 Python
python opencv 读取本地视频文件 修改ffmpeg的方法
Jan 26 Python
Python时间序列处理之ARIMA模型的使用讲解
Apr 02 Python
简单了解Java Netty Reactor三种线程模型
Apr 26 Python
Django权限设置及验证方式
May 13 Python
python gui开发——制作抖音无水印视频下载工具(附源码)
Feb 07 Python
Python线性回归实战分析
Feb 01 #Python
Python使用matplotlib简单绘图示例
Feb 01 #Python
Python解决抛小球问题 求小球下落经历的距离之和示例
Feb 01 #Python
Python 判断 有向图 是否有环的实例讲解
Feb 01 #Python
python使用KNN算法手写体识别
Feb 01 #Python
python @property的用法及含义全面解析
Feb 01 #Python
详解Tensorflow数据读取有三种方式(next_batch)
Feb 01 #Python
You might like
PHP的FTP学习(一)[转自奥索]
2006/10/09 PHP
WML,Apache,和 PHP 的介绍
2006/10/09 PHP
PHP中array_merge和array相加的区别分析
2013/06/17 PHP
从零开始学YII2框架(六)高级应用程序模板
2014/08/20 PHP
Laravel接收前端ajax传来的数据的实例代码
2017/07/20 PHP
PHP简单实现二维数组赋值与遍历功能示例
2017/10/19 PHP
PHP生成指定范围内的N个不重复的随机数
2019/03/18 PHP
PHP配合fiddler抓包抓取微信指数小程序数据的实现方法分析
2020/01/02 PHP
IE6、IE7中setAttribute不支持class/for/rowspan/colspan等属性
2011/08/28 Javascript
JavaScript 32位整型无符号操作示例
2013/12/08 Javascript
关于JavaScript 原型链的一点个人理解
2016/07/31 Javascript
javascript判断firebug是否开启的方法
2016/11/23 Javascript
JavaScript用二分法查找数据的实例代码
2017/06/17 Javascript
js防刷新的倒计时代码 js倒计时代码
2017/09/06 Javascript
如何解决jQuery 和其他JS库的冲突
2020/06/22 jQuery
js+canvas实现刮刮奖功能
2020/09/13 Javascript
[23:21]Ti4 冒泡赛第二轮DK vs C9 2
2014/07/14 DOTA
[01:12:27]EG vs Secret 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
基于python的汉字转GBK码实现代码
2012/02/19 Python
python实现决策树、随机森林的简单原理
2018/03/26 Python
自定义django admin model表单提交的例子
2019/08/23 Python
完美解决pyinstaller打包报错找不到依赖pypiwin32或pywin32-ctypes的错误
2020/04/01 Python
Python几种常见算法汇总
2020/06/02 Python
Python3爬虫里关于代理的设置总结
2020/07/30 Python
python软件测试Jmeter性能测试JDBC Request(结合数据库)的使用详解
2021/01/26 Python
CSS超出文本指定宽度用省略号代替和文本不换行
2016/05/05 HTML / CSS
英国最大的在线奢侈手表零售商:Jura Watches
2018/01/29 全球购物
美国经典刺绣和字母儿童服装特卖:Smocked Auctions
2018/07/16 全球购物
加利福尼亚州威尼斯的女性奢侈品设计师服装和概念店:Mona Moore
2018/09/13 全球购物
金蝶的一道SQL笔试题
2012/12/18 面试题
2014年政务公开工作总结
2014/12/09 职场文书
信仰观后感
2015/06/03 职场文书
励志语录:时光飞逝,请学会珍惜所有的人和事
2020/01/16 职场文书
nginx 防盗链防爬虫配置详解
2021/03/31 Servers
python自动化之如何利用allure生成测试报告
2021/05/02 Python
SpringBoot整合Redis入门之缓存数据的方法
2021/11/17 Redis