Python实现本地视频/音频播放器

Python实现本地视频/音频播放器

在Python中,有几个库可以用于视频播放,但是没有一个库是完美的,因为它们可能依赖于外部软件或有一些限制。

先看介绍用Python实现本地视频播放器,再介绍用Python实现本地音乐播放器。

Python实现本地视频播放器

与HTML5+JavaScript实现本地视频播放器相比,使用Python实现比较麻烦。我发现网上给出的一些示例,通常有一些小问题,如画面和声音不同步等,或有画面没声音的。下面我给出一个简单而效果较好的例子。

Tkinter 是 Python 的一个内置库,它提供了构建图形用户界面 (GUI) 的工具。Tkinter 基于 Tk GUI 工具包。Tkinter 是 Python 标准库的一部分,因此您不需要安装任何额外的包。

                     

ffpyplayer是一个基于FFmpeg的Python多媒体播放库,它可以播放多种格式的视频和音频文件。相比pygame,ffpyplayer支持更多的媒体格式,包括常见的MP4、AVI、MKV、FLV等视频格式,以及MP3、WAV、FLAC等音频格式。

这是第三方库,需要安装, cmd命令行中,输入如下命令:

pip install ffpyplayer

如果你的电脑上安装了多个Python版本,你可以为特定版本的Python安装模块(库、包),还可以使用国内的镜像加快安装速度。例如我的电脑中安装了多个Python版本,要在Python 3.10版本中安装,并使用清华的镜像,cmd命令行中,输入如下命令:

py -3.10 -m pip install ffpyplayer -i https://pypi.tuna.tsinghua.edu.cn/simple

Pillow库是在PIL库的基础上发展起来的,它继承了PIL库的大部分功能,并进行了许多改进和增强。Pillow库已经成为了Python图像处理领域中使用最广泛的库之一,提供了丰富的图像处理功能,包括图片打开、大小调整、裁剪、旋转、滤镜等操作。PIL库在Python 3之后已经停止维护,取而代之的是Pillow库。

这是第三方库,需要安装, cmd命令行中,输入如下命令:

pip install Pillow

如果你的电脑上安装了多个Python版本,你可以为特定版本的Python安装模块(库、包),还可以使用国内的镜像加快安装速度。例如我的电脑中安装了多个Python版本,要在Python 3.10版本中安装,并使用清华的镜像,cmd命令行中,输入如下命令

py -3.10 -m pip install Pillow -i https://pypi.tuna.tsinghua.edu.cn/simple

下面,是Python使用这些库实现的简单的本地视频播放器,给先给出效果图:

源码如下:

import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
from tkinter.ttk import Style, Progressbar
from ffpyplayer.player import MediaPlayer

# 定义视频播放器类
class VideoPlayTk:
    # 初始化函数
    def __init__(self, root):
        self.root = root
        self.root.title('视频播放器')  # 设置窗口标题

        # 创建一个画布用于显示视频帧
        self.canvas = tk.Canvas(root, bg='black')
        self.canvas.pack(fill=tk.BOTH, expand=True)

        # 创建打开文件按钮
        self.open_button = tk.Button(root, text='打开', command=self.open_file)
        self.open_button.pack(side=tk.LEFT)

        # 创建暂停/播放按钮
        self.pause_button = tk.Button(root, text='暂停/继续', command=self.toggle_pause)
        self.pause_button.pack(side=tk.LEFT)

        # 初始化播放器和播放状态标志
        self.player = None
        self.is_paused = False
        self.is_stopped = False

    # 打开文件的函数
    def open_file(self):
        #file_path = filedialog.askopenfilename()  # 弹出文件选择对话框
        file_path = filedialog.askopenfilename(filetypes=[("Video files", "*.mp4;*.avi;*.mov;*.wmv;*.mkv;*.flv;*.mpeg;*.3gp")])
        if file_path:
            self.is_stopped = False
            self.is_paused = False
            self.start_video(file_path)  # 开始播放选择的视频文件

    # 开始播放视频的函数
    def start_video(self, file_path):
        self.player = MediaPlayer(file_path)  # 创建一个MediaPlayer对象
        self.play_video()  # 开始播放视频

    # 播放视频的函数
    def play_video(self):
        if self.is_stopped:
            self.player = None  # 如果停止播放,则释放播放器资源
            return

        frame, val = self.player.get_frame()  # 获取下一帧和帧间隔
        if val == 'eof':
            self.player = None  # 如果到达视频末尾,则释放播放器资源
            return
        elif frame is None:
            self.root.after(10, self.play_video)  # 如果没有帧,则稍后再试
            return

        # 将帧图像转换为Tkinter PhotoImage并显示在画布上
        image, pts = frame
        image = Image.frombytes("RGB", image.get_size(), bytes(image.to_bytearray()[0]))
        photo = ImageTk.PhotoImage(image=image)
        self.canvas.create_image(0, 0, image=photo, anchor=tk.NW)
        self.canvas.image = photo  # 保持对PhotoImage的引用,防止被垃圾回收

        # 如果没有暂停,则继续播放下一帧
        if not self.is_paused:
            self.root.after(int(val * 1000), self.play_video)

    # 切换暂停状态的函数
    def toggle_pause(self):
        if self.player:
            self.is_paused = not self.is_paused  # 切换暂停状态
            self.player.set_pause(self.is_paused)  # 设置播放器的暂停状态
            if not self.is_paused:
                self.play_video()  # 如果继续播放,则播放下一帧

# 程序入口点
if __name__ == '__main__':
    root = tk.Tk()  # 创建Tkinter根窗口
    app = VideoPlayTk(root)  # 创建视频播放器应用
    root.mainloop()  # 进入Tkinter事件循环

下面是改进:带有播放显示时间轴,效果图如下:

源码如下:

import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
from tkinter.ttk import Style, Progressbar
from ffpyplayer.player import MediaPlayer

class VideoPlayTk:
    def __init__(self, root):
        self.root = root
        self.root.title('视频播放器')

        # 创建一个画布用于显示视频帧
        self.canvas = tk.Canvas(root, bg='black')
        self.canvas.pack(fill=tk.BOTH, expand=True)

        # 创建打开文件按钮
        self.open_button = tk.Button(root, text='打开', command=self.open_file)
        self.open_button.pack(side=tk.LEFT)

        # 创建暂停/播放按钮
        self.pause_button = tk.Button(root, text='暂停/继续', command=self.toggle_pause)
        self.pause_button.pack(side=tk.LEFT)

        # 创建时间轴,时间轴指示的时间可能不准确,注意to 值的设置
        self.timeline = tk.Scale(root, from_=0, to=250, orient=tk.HORIZONTAL)
        self.timeline.pack(fill=tk.X)

        # 初始化播放器和播放状态标志
        self.player = None
        self.is_paused = False
        self.is_stopped = False
        self.video_duration = 0

    def open_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("Video files", "*.mp4;*.avi;*.mov;*.wmv;*.mkv;*.flv;*.mpeg;*.3gp")])
        if file_path:
            self.is_stopped = False
            self.is_paused = False
            self.start_video(file_path) # 开始播放选择的视频文件

    def start_video(self, file_path):
        self.player = MediaPlayer(file_path)
        self.video_duration = self.player.get_metadata()['duration']
        self.timeline.config(to=self.video_duration)
        self.play_video() # 开始播放视频 

    def play_video(self):
        if self.is_stopped:
            self.player = None
            return

        frame, val = self.player.get_frame() # 获取下一帧和帧间隔
        if val == 'eof':
            self.player = None
            return
        elif frame is None:
            self.root.after(10, self.play_video) # 如果没有帧,则稍后再试
            return

        # 将帧图像转换为Tkinter PhotoImage并显示在画布上
        image, pts = frame
        image = Image.frombytes("RGB", image.get_size(), bytes(image.to_bytearray()[0]))
        photo = ImageTk.PhotoImage(image=image)
        self.canvas.create_image(0, 0, image=photo, anchor=tk.NW)
        self.canvas.image = photo

        self.timeline.set(pts)  # Update the timeline value(更新时间轴值)

        # 如果没有暂停,则继续播放下一帧
        if not self.is_paused:
            self.root.after(int(val * 1000), self.play_video)

    def toggle_pause(self):
        if self.player:
            self.is_paused = not self.is_paused  # 切换暂停状态
            self.player.set_pause(self.is_paused) # 设置播放器的暂停状态
            if not self.is_paused:
                self.play_video()  # 如果继续播放,则播放下一帧

if __name__ == '__main__':
    root = tk.Tk()
    app = VideoPlayTk(root)
    root.mainloop()


提示,时间轴指示的时间可能不准确。待找到处理方法时更新。

附录

Python使用pillow库(PIL库)的使用介绍 https://blog.csdn.net/cnds123/article/details/126141838

Python简单GUI程序示例(四、视频播放器)https://blog.csdn.net/cnds123/article/details/122903311

Python实现的本地音乐播放器

使用tkinter库来构建用户界面,以及pygame库来处理音频播放。

pygame是一个用于编写游戏和多媒体应用程序的Python模块。它提供了许多功能,包括绘制图形、处理音频、处理输入设备等。功能比较丰富易用

pygame库是第三方库,需要安装, cmd命令行中,输入如下命令:

pip install pygame

如果你的电脑上安装了多个Python版本,你可以为特定版本的Python安装模块(库、包),还可以使用国内的镜像加快安装速度。例如我的电脑中安装了多个Python版本,要在Python 3.10版本中安装,并使用清华的镜像,cmd命令行中,输入如下命令:

py -3.10 -m pip install pygame -i https://pypi.tuna.tsinghua.edu.cn/simple

给先给出效果图:

有打开“按钮”按钮加载音乐文件,“暂停/继续”按钮用于暂停、继续播放,并能显示当前播放的时间(每秒更新/时长)。

源码如下:

import tkinter as tk
from tkinter import filedialog
import pygame
import time

class MusicPlayer:
    def __init__(self, root):
        self.root = root
        self.root.title('Music Player')
        self.root.geometry('400x200')

        pygame.init()
        pygame.mixer.init()

        self.status = 'stopped'
        self.current_time = 0
        self.total_time = 0

        self.load_button = tk.Button(self.root, text='加载音乐', width=10, command=self.load_music)
        self.load_button.pack()

        self.play_button = tk.Button(self.root, text='播放', width=10, command=self.play_music)
        self.play_button.pack()

        self.pause_button = tk.Button(self.root, text='暂停/继续', width=10, command=self.toggle)
        self.pause_button.pack()

        self.time_label = tk.Label(self.root, text='00:00 / 00:00')
        self.time_label.pack()

        self.file_label = tk.Label(self.root, text='加载的音乐文件: ')
        self.file_label.pack()

        self.update_time()

    def load_music(self):
        self.file_path = filedialog.askopenfilename(filetypes=[("Audio files", "*.mp3; *.wav; *.ogg")])
        pygame.mixer.music.load(self.file_path)
        self.total_time = pygame.mixer.Sound(self.file_path).get_length()
        self.file_label.config(text='加载的音乐文件: ' + self.file_path)

    def play_music(self):
        if self.status != 'playing':
            pygame.mixer.music.play()
            self.status = 'playing'

    def toggle(self):
        if self.status == 'paused':
            pygame.mixer.music.unpause()
            self.status = 'playing'
        elif self.status == 'playing':
            pygame.mixer.music.pause()
            self.status = 'paused'

    def update_time(self):
        if self.status == 'playing':
            self.current_time = pygame.mixer.music.get_pos() // 1000
            mins, secs = divmod(self.current_time, 60)
            timeformat = '{:02d}:{:02d}'.format(mins, secs)
            total_mins, total_secs = divmod(int(self.total_time), 60)
            total_timeformat = '{:02d}:{:02d}'.format(total_mins, total_secs)
            self.time_label.config(text='{} / {}'.format(timeformat, total_timeformat))
        self.root.after(1000, self.update_time)

if __name__ == "__main__":
    root = tk.Tk()
    app = MusicPlayer(root)
    root.mainloop()

附录

Python中的pygame游戏模块的使用 https://blog.csdn.net/cnds123/article/details/119514520

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/575033.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS Position定位(详解网页中的定位属性)

目录 一、Position介绍 1.概念 2.特点 3.作用 4.应用 二、Position用法 1.position属性 2.static定位 3.fixed定位 4.relative定位 5.absolute定位 6.sticky定位 7.重叠的元素 三、CSS定位属性 四、总结 一、Position介绍 1.概念 文档流(Document Fl…

【从后端日志文件中过滤出sql语句】

从后端日志文件中过滤出sql语句 why?思路日志文件的格式 结果 why? 为什么会有这种需求?,mysql数据不小心被删了完全可以从备份数据恢复,或者从binlog中恢复,但是如果前面这两种方法没办法处理(没有备份数据库文件、…

ray.tune调参学习笔记1:超参数优化器tuner设置

最近研究中学习使用python的ray.tune进行神经网络调参。在这里记录学习过程中的收获,希望能够帮助到有同样需求的人。学习过程主要参考ray官网文档,但由于笔者使用的ray为2.2.0版本,而官方文档为更高级版本,笔者代码和官方文档代码…

数字藏品:重塑艺术与科技的新媒介

数字藏品,这个新兴的词汇,正在逐渐渗透到我们的日常生活中。它不仅是一种新的艺术表达方式,更是一种科技与艺术相结合的全新媒介。那么,数字藏品究竟是什么呢? 首先,我们需要明确一点,数字藏品并…

qt QTreeWidget 学习

树形控件的节点可以有多层、多个子节点, 如果将子节点全部展开,那么每一行都是一个数据条目。QTreeWidgetItem 比较特殊,一个条目内部可以有多列数据信息,相当于表格控件一整行的表格单元集成为一个条目。 默认情况下,…

ELK技术介绍:背景、功能及应用场景全面解析

一、ELK概述 ELK是由Elasticsearch、Logstash和Kibana三个开源软件组成的日志管理解决方案,这一组合在近年来得到了广泛的关注和应用。ELK的出现,源于大数据和云计算技术的快速发展,以及对高效日志管理的迫切需求。 随着企业信息化程度…

Nginx 配置 SSL(HTTPS)详解

Nginx作为一款高性能的HTTP和反向代理服务器,自然支持SSL/TLS加密通信。本文将详细介绍如何在Nginx中配置SSL,实现HTTPS的访问。 随着互联网安全性的日益重要,HTTPS协议逐渐成为网站加密通信的标配。Nginx作为一款高性能的HTTP和反向代理服务…

6、ES单机设置用户名密码、集群设置用户名密码、es-head登录、如何去掉密码

目录 一、ES单节点密码配置1、修改配置文件2、 重启es服务3,执行修改密码命令4、访问服务 二、ES集群密码配置1、确定主节点2、生成elastic-stack-ca.p123、生成elastic-certificates.p124、修改配置文件并重启集群5、进行密码配置6、验证 三、es-head登录增加密码的…

ABAP json解析使用引用代替预定义数据结构

背景:在解析JSON数据时,通常会事先为定义相应的ABAP数据结构。但是,当遇到一些结构纵深较为复杂的情况时,会比较麻烦。 处理:使用引用类型来定义结构中的纵深部分来达到“省事”的目的,缺点在于访问时需要使…

Docker——开源的应用容器的引擎

目录 一、前言 1.虚拟化产品有哪些 1.1寄居架构 1.2源生架构 2.虚拟化产品对比/介绍 2.1虚拟化产品 2.1.1仿真虚拟化 2.1.2半虚拟化 2.1.3全虚拟化 2.2重点 2.2.1KVM——Linux内核来完成的功能和性能 2.2.2ESXI——用的比较多 二、Docker概述 1.Docker定义 2.Do…

赋能智慧校园!A3D数字孪生可视化,轻量又高效!

放假之后,学生们会逐步返学,大量人员出入校园,安全更是不容忽视,如何在短时间内对大批人员及设施进行智能监管?数字化转型是关键手段,我们可以融合线上线下数据,搭建3D立体的智慧校园&#xff0…

智能合约——提案demo

目录 这是一个超超超级简单的智能合约提案项目,你确定不点进来看一下吗? 引言: 1、搭建开发环境: 2、编写智能合约: 3、部署智能合约: ​编辑​编辑4、编写前端交互代码(使用web3.js&…

MyBatis源码之MyBatis中SQL语句执行过程

MyBatis源码之MyBatis中SQL语句执行过程 SQL执行入口 我们在使用MyBatis编程时有两种方式&#xff1a; 方式一代码如下&#xff1a; SqlSession sqlSession sqlSessionFactory.openSession(); List<Student> studentList sqlSession.selectList("com.sjdwz.da…

C语言——自定义数据类型(结构体内存对齐)

C语言中不只有内置类型诸如 int 、float、char 等类型&#xff0c;还有自定义数据类型&#xff0c;本文主要探讨结构体&#xff08;struct&#xff09;、联合体&#xff08;union&#xff09;、枚举&#xff08;enum&#xff09;三种自定义数据类型。 在我之前的文章《C语言—…

WPF2 样式布局

样式布局 WPF中的各类控件元素, 都可以自由的设置其样式。 诸如: 字体(FontFamily) 字体大小(FontSize) 背景颜色(Background) 字体颜色(Foreground) 边距(Margin) 水平位置(HorizontalAlignment) 垂直位置(VerticalAlignment) 等等。 而样式则是组织和重用以上的重要工具。…

解码Linux中的Shell:一探脚本起源、发展与变量数据类型之奥秘

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Linux &#xff1a;从菜鸟到飞鸟的逆袭》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、Linux的起源与发展 2、什么是Shell脚本 3、Sh…

MySQL面试——聚簇/非聚簇索引

存储引擎是针对表结构&#xff0c;不是数据库 引擎层&#xff1a;对数据层以何种方式进行组织 update&#xff1a;加索引&#xff1a;行级锁&#xff1b;不加索引&#xff1a;表级锁

LabVIEW专栏七、队列

目录 一、队列范例二、命令簇三、队列应用1.1、并行循环队列1.2、命名队列和匿名队列1.2.1、命名队列1.2.2、匿名队列 1.3、长度为1的队列 队列是一种特殊的线性表&#xff0c;就是队列里的元素都是按照顺序进出。 队列的数据元素又称为队列元素。在队列中插入一个队列元素称为…

HNCTF 2022 week1 题解

自由才是生活主旋律。 [HNCTF 2022 Week1] Interesting_include <?php //WEB手要懂得搜索 //flag in ./flag.phpif(isset($_GET[filter])){$file $_GET[filter];if(!preg_match("/flag/i", $file)){die("error");}include($file); }else{highlight_…

OSPF的协议特性

路由汇总的概念 l 路由汇总&#xff08; Route Aggregation &#xff09;&#xff0c;又称路由聚合&#xff08;Route Summarization&#xff09;&#xff0c;指的是把一组明细路由汇聚成一条汇总路由条目的操作 l 路由汇总能够减少路由条目数量、减小路由表规模&#xff0…
最新文章