Closed cosven closed 7 years ago
背景描述,在Linux下,想使用 Qt 的 QtMultiMeida 这个模块写一个播放器,它在播放音乐的时候可以缓存这首音乐。
这样可以很简单
from PyQt5.QtWidgets import * from PyQt5.QtMultimedia import * from PyQt5.QtGui import * from PyQt5.QtCore import * app = QtWidgets.QApplication(sys.argv) mp3_url = 'http://m1.music.126.net/Gybpf5bX9zfNesjXxZl3qw==/2053887720715417.mp3' player = QMediaPlayer() player.setMedia(QMediaContent(QUrl(mp3_url))) player.play() w = Widget() w.show() sys.exit(app.exec_())
思路描述:之前以为可以很简单的写一个带缓存的版本。以为 QMediaPlayer,QtMultiMedia 这个模块提供了相关函数可以直接拿到缓存,不过经过一番探索,没能找到办法。 所以第二个思路,自己控制mediacontent. 也就是说我用 requests 先把音乐下载下来,然后在播放。恩,这样的确可以,但是常规办法貌似不能 边下载,边播放。所以想到了 QMediaPlayer 的 stream 播放模式,利用多线程,一个线程下载,一个线程播放。player = QMediaPlayer(flags=QMediaPlayer.StreamPlayback)
思路描述:之前以为可以很简单的写一个带缓存的版本。以为 QMediaPlayer,QtMultiMedia 这个模块提供了相关函数可以直接拿到缓存,不过经过一番探索,没能找到办法。
所以第二个思路,自己控制mediacontent. 也就是说我用 requests 先把音乐下载下来,然后在播放。恩,这样的确可以,但是常规办法貌似不能 边下载,边播放。所以想到了 QMediaPlayer 的 stream 播放模式,利用多线程,一个线程下载,一个线程播放。player = QMediaPlayer(flags=QMediaPlayer.StreamPlayback)
stream
player = QMediaPlayer(flags=QMediaPlayer.StreamPlayback)
代码如下:
#! /usr/bin/env python3 import sys import time from PyQt5 import QtWidgets from PyQt5.QtWidgets import * from PyQt5.QtMultimedia import * from PyQt5.QtGui import * from PyQt5.QtCore import * from _thread import start_new_thread import requests import os mp3_url = 'http://m1.music.126.net/Gybpf5bX9zfNesjXxZl3qw==/2053887720715417.mp3' # 这首歌时间较短 mp3_url = 'http://m2.music.126.net/Jx2_zeePijuCGjqGSgTGyw==/6656443395918618.mp3' # 这首歌时间较长 mp3_url = 'http://m2.music.126.net/7tEJKStKIbxKPVKw7urYkA==/6033020302257380.mp3' # 这首歌时间很长 global i i = 0 def print_duration(duration): time_text = QTime(0, (duration / 60000) % 60, (duration/ 1000) % 60) print("duration:", time_text.toString("mm:ss")) def print_position(position): time_text = QTime(0, (position/ 60000) % 60, (position/ 1000) % 60) print('position:', time_text.toString("mm:ss"), i) def print_media_changed(media): print ("media changed") def print_buffer(status): print ('buffer', status) class Player(QObject): def __init__(self): super().__init__() self.player = QMediaPlayer(flags=QMediaPlayer.StreamPlayback) # self.player.positionChanged.connect(print_position) self.player.durationChanged.connect(print_duration) self.player.currentMediaChanged.connect(print_media_changed) self.player.bufferStatusChanged.connect(print_buffer) self.tmp_pos = 0 def start(self): print('start') start_new_thread(self.async, ()) time.sleep(2) self.player.setMedia(QMediaContent(), self.music) self.player.play() def async(self): global i self.res = requests.get(mp3_url, stream=True) self.music = QFile('temp.mp3') # self.music = QBuffer() flag = self.music.open(QIODevice.ReadWrite) for chunk in self.res.iter_content(1024000): print('i:', i, end='') self.player.pause() self.music.seek(self.music.size()) print ('file seek pos: ', self.music.pos(), end='') self.music.write(chunk) # 这里有问题 print ('file seek pos: ', self.music.pos()) self.player.play() i += 1 print("finished") class Widget(QWidget): def __init__(self): super().__init__() self.player = Player() self.button = QPushButton('play', self) self.button.clicked.connect(self.player.start) app = QtWidgets.QApplication(sys.argv) w = Widget() w.show() sys.exit(app.exec_())
看似上面的代码可以实现缓存,但是实践发现存在一个问题。这一段
补充背景知识:player 在播放的时候,也会读 self.music 这个文件,所以它也会控制 self.music文件指针,seek到了文件的某个位置。
self.music
self.player.pause() self.music.seek(self.music.size()) # print ('file seek pos: ', self.music.pos(), end='') self.music.write(chunk) # 这里有问题,有可能不会写到文件的末尾,而是文件的某个地方 print ('file seek pos: ', self.music.pos()) self.player.play()
所以换句话说,上面的问题变成了 多个线程操作一个文件 出现了冲突。但是它又有
背景描述,在Linux下,想使用 Qt 的 QtMultiMeida 这个模块写一个播放器,它在播放音乐的时候可以缓存这首音乐。
不缓存音乐
这样可以很简单
带缓存的版本(未实现)
代码如下:
看似上面的代码可以实现缓存,但是实践发现存在一个问题。这一段
所以换句话说,上面的问题变成了 多个线程操作一个文件 出现了冲突。但是它又有