Python Forum
Pyglet Media: unjustifiable memory usage
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Pyglet Media: unjustifiable memory usage
#1
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.
#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.
Reply
#2
The docs advise using:
music = pyglet.resource.media('music.mp3')
music.play()
see: http://pythonhosted.org/pyglet/programmi...music.html

I am not familiar with this package, but will show this anyway
Reply
#3
(Aug-19-2017, 04:04 PM)Larz60+ Wrote: The docs advise using:
music = pyglet.resource.media('music.mp3')
music.play()

pyglet.resource.media and pyglet.media.load[I used] both are same.
[inline] pyglet.resource.media locates the sound file in the application's directory (not the working directory).
If you know the actual filesystem path (either relative or absolute), use pyglet.media.load.[/inline]

They just load the source and return source object which is passed to the player. I think the problem is with player object, but then my alternate method didn't work either.
Reply
#4
(Aug-19-2017, 02:54 PM)hbknjr Wrote: 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.
Pyglet use Python garbage collector to release stuff from memory.
There is a Player.delete() method that release resources immediately.
They doc for this is here.
Reply
#5
(Aug-19-2017, 08:06 PM)snippsat Wrote: Pyglet use Python garbage collector to release stuff from memory.
There is a Player.delete() method that release resources immediately.
I tried that in second method:

(Aug-19-2017, 02:54 PM)hbknjr Wrote: Here's an alternate way I tried by deleting the player object, calling gc, and recreating it but no success.

    #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

But the above code doesn't effect the memory usage at all. I also tried del which obviously doesn't work as song keeps playing in background, assigning self.player=None and calling gc also didn't work. Tell me where I'm wrong.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  How would I be able to detect a media player app playing a video. phpjunkie 2 526 Oct-16-2023, 02:09 PM
Last Post: phpjunkie
  Python & Windows Media Player Extra 9 4,749 Apr-05-2022, 10:34 PM
Last Post: Extra
  Playing mp3 with pyglet constantin01 3 5,434 Dec-17-2021, 01:14 PM
Last Post: Legumen
  Reducing runtime memory usage in Cpython interpreter david_the_graower 2 2,175 Oct-18-2021, 09:56 PM
Last Post: david_the_graower
  Adding variable to Python code - media sentiment analysis Marietje 3 2,511 May-25-2021, 05:15 PM
Last Post: jefsummers
  pyglet problem deansenecal 1 1,902 Feb-15-2021, 11:15 PM
Last Post: Larz60+
  Python - Import file sequence into Media Pool jensenni 1 2,080 Feb-02-2021, 05:11 PM
Last Post: buran
  How many times was the button pressed in pyglet rama27 0 1,888 Oct-10-2020, 10:26 AM
Last Post: rama27
  Open windows media player minimised TamP 1 2,169 Aug-02-2020, 08:40 PM
Last Post: Larz60+
  MEDIA ROOT ionezation 1 2,157 Mar-29-2019, 02:43 PM
Last Post: ichabod801

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020