Aug-19-2017, 02:54 PM
Hi,
I was recommended Pyglet for creating music player Here. I encountered an issue of high memory usage while playing mp3 files.
PROBLEM: I created a player object and loaded/queued some mp3s but each time when I use the next_source method to play the next queued mp3 it takes around 50-80mb of additional RAM. I tried to use memory_profiler but in vain.
Here are the steps to recreate the issue:
1: Run below code in a directory with few mp3 files, and plz make sure to fulfill requirements.
I was recommended Pyglet for creating music player Here. I encountered an issue of high memory usage while playing mp3 files.
PROBLEM: I created a player object and loaded/queued some mp3s but each time when I use the next_source method to play the next queued mp3 it takes around 50-80mb of additional RAM. I tried to use memory_profiler but in vain.
Here are the steps to recreate the issue:
1: Run below code in a directory with few mp3 files, and plz make sure to fulfill requirements.
#requirements
#Pyglet
#http://avbin.github.io/AVbin/Download.html
#https://pypi.python.org/pypi/memory_profiler
import os
import fnmatch
from memory_profiler import profile
from pyglet.media import *
from pyglet.media.avbin import AVbinException
class MusicPlayerCore():
def __init__(self):
self.player = Player()
self.loadsource()
#loading all mp3 in player
@profile
def loadsource(self):
songpathlist = self.recur_searchindir()
for song in songpathlist:
try:
source = load(song)
self.player.queue(source)
except AVbinException:
pass
@profile
def play(self):
self.player.play()
def pause(self):
self.player.pause()
@profile
def next(self):
self.player.next_source()
#Find all mp3 in current directory of script
def recur_searchindir(self):
directory = os.path.dirname(os.path.realpath(__file__))
songpathlist = []
for root, dirnames, filenames in os.walk(directory):
for filename in fnmatch.filter(filenames, '*.mp3'):
songpathlist.append(os.path.join(root, filename))
return songpathlist
def main():
player = MusicPlayerCore()
while 1:
print("1-Play \n 2-Pause \n 3- Play Next\n 4- Exit")
ch = int(input("Enter choice:"))
if ch == 1:
player.play()
elif ch == 2:
player.pause()
elif ch == 3:
player.next()
elif ch == 4:
break
else:
print("Wrong choice")
if __name__ == "__main__":
main()
Here's an alternate way I tried by deleting the player object, calling gc, and recreating it but no success.#requirements
#Pyglet
#http://avbin.github.io/AVbin/Download.html
#https://pypi.python.org/pypi/memory_profiler
import os
import fnmatch
import gc
from memory_profiler import profile
from pyglet.media import *
from pyglet.media.avbin import AVbinException
class MusicPlayerCore():
def __init__(self, songlist):
self.songlist = songlist #list of path of all songs in dir
self.player = Player() #pyglet player object
self.songnav = NextandPrev(songlist)
self.currentsong = songlist[0] # path of current song | initially first song
self.loadsource() # load currentsong
#loading current song in player
@profile
def loadsource(self):
try:
source = load(self.currentsong)
self.player.queue(source)
except AVbinException:
self.songnavupdate_next()
#updating previous and current song path
@profile
def songnavupdate_next(self):
if self.songnav.n_song != None:
self.makenewplayer() # create new player object
self.currentsong = self.songnav.n_song
self.songnav.remake_list(self.currentsong)
self.loadsource()
#updating previous and current song path
@profile
def songnavupdate_prev(self):
if self.songnav.p_song !=None:
self.makenewplayer() # create new player object
self.currentsong = self.songnav.p_song
self.songnav.remake_list(self.currentsong)
self.loadsource()
#Make a new Player object, deleting previous one
@profile
def makenewplayer(self):
'''memory_profiler shows no change in memory usage here'''
self.player.delete() #deleting current player object
#del self.player
gc.collect() #explicitly calling gc.collect to remove out of scope player object
self.player = Player() #new player object
@profile
def play(self):
self.player.play()
def pause(self):
self.player.pause()
@profile
def play_next(self):
self.songnavupdate_next()
self.player.play()
@profile
def play_prev(self):
self.songnavupdate_prev()
self.player.play()
class NextandPrev():
def __init__(self, songlist):
self.songlist = songlist
self.n_song = songlist[1]
self.p_song = None
def remake_list(self, current_song):
index = self.songlist.index(current_song)
try:
self.n_song = self.songlist[index + 1]
except IndexError:
self.n_song = None
try:
self.p_song = self.songlist[index - 1]
except IndexError:
self.p_song = None
#Find all mp3 in current directory of script
def recur_searchindir():
directory = os.path.dirname(os.path.realpath(__file__))
songpathlist = []
for root, dirnames, filenames in os.walk(directory):
for filename in fnmatch.filter(filenames, '*.mp3'):
songpathlist.append(os.path.join(root, filename))
return songpathlist
def main():
songpathlist = recur_searchindir()
player = MusicPlayerCore(songpathlist)
while 1:
print("1-Play \n 2-Pause \n 3- Play Next\n 4- Previous \n 5- Exit")
ch = int(input("Enter choice:"))
if ch == 1:
player.play()
elif ch == 2:
player.pause()
elif ch == 3:
player.play_next()
elif ch == 4:
player.play_prev()
elif ch == 5:
break
else:
print("Wrong choice")
if __name__ == "__main__":
main()I also tried to understand the pyglet code but it is too optimized for readability and I'm not pro enough.
