I am trying to set volume while playing an audio file but it doesn't seem to work at all. Please what am I doing wrong?
# create a vlc playable object from source
self.playable = vlc.libvlc_media_new_path(self.instance, sourceURL)
# create a new vlc player
self.player = vlc.libvlc_media_player_new_from_media(self.playable)
# play
vlc.libvlc_media_player_play(self.player)
while not self.stop:
sleep(10) # sleep for a while to allow playback
self.player.audio_set_volume(50) # suppose to reduce volume. Doesn't work
sleep(10) # sleep for a while to allow playback
self.stop = True
UPDATE try the following:
self.instance = vlc.Instance()
self.mediaplayer = self.instance.media_player_new()
self.media = self.instance.media_new(unicode(sourceURL))
self.mediaplayer.set_media(self.media)
self.media.parse()
while True :
sleep(10)
self.mediaplayer.audio_set_volume(50)
Example usage
Keep in mind that volume_level is an integer between 0 and 100, 100 will be equal to 0db.
Made a big edit because I think I originally misunderstood a bit. Does the video output work for you?
Related
I'd like to the ability to run some code when the timestamp of a file has been reached (i.e. trigger an alert)
How can this be achieved?
I was looking at this https://www.geeksforgeeks.org/python-vl ... edia-time/
However, I feel like I'm really looking for some kind of daemon (i.e. start the media file with VLC and then have this "listener" perform an action when timestamp on vlc has been reached)
I'm not opposed to pulling down the code, modifying changes to add a hook, and re-compiling to get what I need. I just need some pointers on where in the codebase this would all live.
What direction may I be pointed to to achieve this? Thanks!
You want the EventManager class, the documentation for which can be found
here. Here's an example of how to use it to notify you when a video stops playing.
import vlc
def callback(event, player):
print('FPS:', player.get_fps())
print('Time(ms):', player.get_time())
print('Frame:', .001 * player.get_time() * player.get_fps())
# Create new media
inst = vlc.Instance()
media = inst.media_new('path/to/video')
# Create new instance of vlc player
player = inst.media_player_new()
# Add a callback
em = player.event_manager()
em.event_attach(vlc.EventType.MediaPlayerStopped, \
callback, player)
# Load video into vlc player instance
player.set_media(media)
# Play media
player.play()
Edit: Could you try this code?
import vlc
def callback(player):
print('FPS:', player.get_fps())
print('Time(ms):', player.get_time())
print('Frame:', .001 * player.get_time() * player.get_fps())
media_player.stop()
# creating vlc media player object
media_player = vlc.MediaPlayer()
# media object
media = vlc.Media("src/backtalk/default/oscar.mp4")
# setting media to the media player
media_player.set_media(media)
# start playing video
media_player.play()
while True:
if media_player.get_state() == vlc.State.Ended:
callback(media_player)
Version of pyglet - 1.4.2. Python - 3.6.6Ubuntu - 18.04
Code example:
import pyglet
import time
pyglet.options['audio'] = ('openal', 'pulse', 'directsound', 'silent')
source = pyglet.media.StaticSource(pyglet.media.load('explosion.wav'))
def my_playlist():
while True:
print(time.time())
print(1)
yield source
player = pyglet.media.Player()
player.queue(my_playlist())
player.play()
pyglet.app.run()
Code was writed based on documentation:
Logs in console:
1566296930.8165386 # played once
1
1566296931.529639 # won't play
1
1566296931.5301056 # won't play and etc.
1
1566296931.5304687
1
1566296931.5309348
1
Expected result:
Audio should play in loop with sounds which is returned from generator.
Current result:
Audio is played once.
Question:
What I did wrong here and how to achive expected result?
Not sure if you're trying to accomplish something more, but if all you need from your loop is to loop sound, you shouldn't actually use a loop of any kind. Instead, use the designated EOS_LOOP flag/trigger.
import pyglet
import time
pyglet.options['audio'] = ('openal', 'pulse', 'directsound', 'silent')
source = pyglet.media.StaticSource(pyglet.media.load('explosion.wav'))
player = pyglet.media.Player()
player.queue(source)
player.EOS_LOOP = 'loop'
player.play()
pyglet.app.run()
And since it's deprecated, you should move away to using the SourceGroup with the loop flag set.
I'm trying to make a simple script that will play a video (.mp4) in python. I don't want to play a you tube video or anything online, just a video on my computer.
Here's my code:
import vlc
Instance = vlc.Instance()
player = Instance.media_player_new()
Media = Instance.media_new('test.mp4')
Media.get_mrl()
player.set_media(Media)
player.play()
I keep getting this error when I run it (talking about line 3):
AttributeError: 'NoneType' object has no attribute 'media_player_new'
I'm using python 3.5.4 in the IDLE on macOS Sierra.
I solved the problem by comment out find_lib() in vlc.py.
p = os.getcwd()
os.chdir(os.path.join(p, 'sdk'))
dll = ctypes.CDLL("libvlc.dll")
plugin_path = os.path.join(os.getcwd(), r'sdk\plugins')
You are not holding the instance open
import vlc
Instance = vlc.Instance()
player = Instance.media_player_new()
Media = Instance.media_new('2005.mp3')
Media.get_mrl()
player.set_media(Media)
player.play()
while player.get_state() !=6:
continue
Should work or
try this:
import vlc
import time
import sys
def progressbar(progress,guage_length=50):
div = 100 / float(guage_length)
prog = int(progress / div) # ensure progress fits in guage
text = "\rPlaying: {0}{1}{2} [{3}%]".format(">"*prog,"|","-"*(guage_length - prog),format(progress,'.2f'))
sys.stdout.write(text)
sys.stdout.flush()
instance = vlc.Instance()
player = instance.media_player_new()
player.set_mrl("V2.mp4")
player.play()
playing = set([1,2,3,4])
play=True
guage_length=30
while play == True:
time.sleep(0.5)
play_state = player.get_state()
if play_state in playing:
length = player.get_length()
ptime = player.get_time()
progress = ptime/float(length)*100
progressbar(progress,guage_length)
continue
else:
progressbar(100,guage_length)
play = False
print ("\nPlay terminated")
Note that # State 0: None,1 Opening,2 Buffering,3 Playing,4 Paused,5 Stopped,6 Ended,7 Error
Caveat: tested on Linux only
You could simplify your code using simply
import vlc
p = vlc.MediaPlayer('2005.mp3')
p.play()
but this would not solve your problem. Apparently, the vlc instance is not correctly created. This can be caused by a variety of issues. Use
i = vlc.Instance('--verbose 3')
to see possible error messages.
I got this error message on a Raspberry Pi Zero with Raspbian Buster Lite. I searched a long time for the answer but suddenly I noticed the remark on the pypi project page of python-vlc:
Note that it relies on an already present install of VLC.
So installing vlc with sudo apt install vlc solved the problem!
I'm using a MediaListPlayer instance to execute a playlist. On a standard MediaPlayer instance you can use MediaPlayer.audio_set_volume(newVolume), but when I try to use the same method(audio_set_volume(newVolume)) on a MediaListPLayer instance, I get an error.:
AtributeError: 'MediaListPLayer' object has no attribute 'audio_set_volume'. What is the replacement of that method for the MediaListPlayer?
This is the code:
from vlc import Instance
playlist = ['/home/user/Music/01 Signs.mp3','/home/user/Music/2U.mp3']
player = Instance()
mediaListPlayer = player.media_list_player_new()
mediaList = player.media_list_new()
for element in playlist:
mediaList.add_media(player.media_new(element))
mediaListPlayer.set_media_list(mediaList)
mediaListPlayer.play()
mediaListPlayer.audio_set_volume(80)
Two years later was wondering the same thing. So here is a solution that worked for me:
import vlc
inst = vlc.Instance()
player = inst.media_list_player_new()
media_list = inst.media_list_new(["example.mp3"])
player.set_media_list(media_list)
player.play()
player.get_media_player().audio_set_volume(50)
MediaListPlayer.get_media_player() returns the MediaPlayer that can be used to control the volume of the MediaListPlayer during playback.
As I said in my comment, it does look like an oversight.
However, I have managed to set the initial volume by hacking a sub_player but once it is set and you invoke the list player, I haven't found a way of adjusting it after that.
import vlc
import time
playlist=['/home/rolf/vp1.mp3','/home/rolf/vp.mp3']
inst = vlc.Instance()
sub_player = inst.media_player_new()
player = inst.media_list_player_new()
mediaList = inst.media_list_new(playlist)
player.set_media_list(mediaList)
volume = 60
sub_player.audio_set_volume(volume)
sub_player.play()
playing = set([1,2,3,4])
player.play()
while player.get_state() in playing:
time.sleep(1)
I have posted a question on videolan ,https://forum.videolan.org/viewtopic.php?f=32&t=139505 so someone with a greater knowledge of these things might provide a better solution. If I get an answer, I'll post it here.
I have 4 video files (different scenes of a movie).
There's a starting scene that will be played when I run the player.
And before that scene ends, let's say the video player reads an int value (0-100) from external file (all happens at runtime), and depending on that int value, it has to determine which scene to play next.
pseudo example:
if (x > 0 && x < 30)
videoSource = scene2
else if (x >= 30 && x < 60)
videoSource = scene3
else if (x >= 60 && x <= 100)
videoSource = scene 4
How can I make it change video sources at runtime, depending on that variable?
I don't care about the format of the video file, (Avi, mp4...) whatever works will be fine.
I don't know how to approach this problem. I've searched for something that has the potential to accomplish this, like pyglet or GStreamer, but I didn't find a clear solution.
EDIT: I have the basic player and video player with pyglet, and I was able to play the video without depending on a variable using this code:
import pyglet
vidPath="sample.mpg"
window = pyglet.window.Window()
player = pyglet.media.Player()
source = pyglet.media.StreamingSource()
MediaLoad = pyglet.media.load(vidPath)
player.queue(MediaLoad)
player.play()
#window.event
def on_draw():
window.clear()
if player.source and player.source.video_format:
player.get_texture().blit(0,0)
pyglet.app.run()
How would I go about this? Guidance in the right direction and/or some sample code would be highly appreciated.
Thanks in advance.
Answer revised based on comments
If your goal is to constantly read a file that is receiving writes from the output of another process, you have a couple aspects that need to be solved...
You either need to read a file periodically that is constantly being overwritten, or you need to tail the output of a file that is being appended to with new values.
Your script currently blocks when you start the pyglet event loop, so this file check will have to be in a different thread, and then you would have to communicate the update event.
I can't fully comment on step 2 because I have never used pyglet and I am not familiar with how it uses events or signals. But I can at least suggest half of it with a thread.
Here is a super basic example of using a thread to read a file and report when a line is found:
import time
from threading import Thread
class Monitor(object):
def __init__(self):
self._stop = False
def run(self, inputFile, secs=3):
self._stop = False
with open(inputFile) as monitor:
while True:
line = monitor.readline().strip()
if line.isdigit():
# this is where you would notify somehow
print int(line)
time.sleep(secs)
if self._stop:
return
def stop(self):
self._stop = True
if __name__ == "__main__":
inputFile = "write.txt"
monitor = Monitor()
monitorThread = Thread(target=monitor.run, args=(inputFile, 1))
monitorThread.start()
try:
while True:
time.sleep(.25)
except:
monitor.stop()
The sleep loop at the end of the code is just a way to emulate your event loop and block.
Here is a test to show how it would work. First I open a python shell and open a new file:
>>> f = open("write.txt", 'w+', 10)
Then you can start this script. And back in the shell you can start writing lines:
>>> f.write('50\n'); f.flush()
In your script terminal you will see it read and print the lines.
The other way would be if your process that is writing to this file is constantly overwriting it, you would instead just reread the file by setting monitor.seek(0) and calling readline().
Again this is a really simple example to get you started. There are more advanced ways of solving this I am sure. The next step would be to figure out how you can signal the pyglet event loop to call a method that will change your video source.
Update
You should review this section of the pyglet docs on how to create your own event dispatcher: http://pyglet.org/doc/programming_guide/creating_your_own_event_dispatcher.html
Again, without much knowledge of pyglet, here is what it might look like:
class VideoNotifier(pyglet.event.EventDispatcher):
def updateIndex(self, value):
self.dispatch_events('on_update_index', value)
VideoNotifier.register_event('on_update_index')
videoNotifier = VideoNotifier()
#videoNotifier.event
def on_update_index(newIndex):
# thread has notified of an update
# Change the video here
pass
And for your thread class, you would pass in the dispatcher instance, and use the updateIndex() event to notify:
class Monitor(object):
def __init__(self, dispatcher):
self._stop = False
self._dispatcher = dispatcher
def run(self, inputFile, secs=3):
...
...
# should notify video of new value
line = int(line_from_file)
self._dispatcher.updateIndex(line)
...
...
Hope that gets you started!