matham / ffpyplayer

A cython implementation of an ffmpeg based player.
GNU Lesser General Public License v3.0
134 stars 37 forks source link

MediaPlayer Sound Still Coming From Speaker After player.set_mute(True) #94

Open slalomchip opened 4 years ago

slalomchip commented 4 years ago

I wrote a script in Python 3.8 on a Windows 10 platform that uses MediaPlayer to play a video in a PyQt5 QLabel. I can toggle pause by pressing the "P" key on the keyboard but I cannot toggle mute when pressing the "M" key.

When pressing the "M" key, the player.get_mute() return changes from False to True to False just as I expect it to, but sound keeps coming out of the speaker regardless if player.get_mute() == True

Here is a minimal script that exhibits this behavior.

from PyQt5.QtWidgets import QLabel, QMainWindow, QApplication, QWidget
from PyQt5.QtWidgets import QShortcut
from PyQt5.QtGui import QPixmap, QImage, QKeySequence
from PyQt5.QtCore import QTimer, Qt
import os, sys
from ffpyplayer.player.player import MediaPlayer

class VideoCap(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Mute Test")        
        self.central_widget = QWidget()               
        self.setCentralWidget(self.central_widget)
        self.central_widget.setGeometry(10,50,960,720)
        self.player = MediaPlayer('test.mp4')
        self.setGeometry(25,50,960,720)
        self.vidWindow = QLabel(self.central_widget)
        self.vidWindow.setGeometry(0,0,960,720)
        self.muteKey = QShortcut(QKeySequence(Qt.Key_M), self)
        self.muteKey.activated.connect(self.toggleMute)
        self.pauseKey = QShortcut(QKeySequence(Qt.Key_P), self)
        self.pauseKey.activated.connect(self.togglePause)
        self.show()
        self.start()

    def nextFrameSlot(self):        
        try:
            frame, val = self.player.get_frame()
            if val != 'eof':
                img, t = frame
                data = img.to_bytearray()[0]
                width, height = img.get_size()
                qimage = QImage(data, width, height, QImage.Format_RGB888)
                pix = QPixmap.fromImage(qimage)
                pix = pix.scaled(self.vidWindow.width(), self.vidWindow.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
                self.vidWindow.setPixmap(pix)
        except:
            pass

    def toggleMute(self):
        isMuted = self.player.get_mute()
        print('Muted = ', isMuted)
        if isMuted == True:
            self.player.set_mute(False)
            print('Should now be unmuted')
        else:
            self.player.set_mute(True)
            print('Should now be muted')

    def togglePause(self):
        isPaused = self.player.get_pause()
        print('Paused = ', isPaused)
        if isPaused == True:
            self.player.set_pause(False)
            print('Should now be playing')
        else:
            self.player.set_pause(True)
            print('Should now be paused')

    def start(self): # Control the timer for calling nextframeslot
        frame_rate = 30.0
        rate = int(1000.0 / frame_rate)
        self.timer = QTimer()
        self.timer.setTimerType(Qt.PreciseTimer)
        self.timer.timeout.connect(self.nextFrameSlot)
        self.timer.start(rate)

    def closeEvent(self, event):
        event.ignore()
        self.player.close_player()
        os._exit(0)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = VideoCap()
    app.exec()
slalomchip commented 4 years ago

Please note that when I pasted in the code block above, I couldn't get the import lines nor the if __name__ == __main__ in the code block. Also, the underscores in if __name__ == __main__ got stripped out. Weird.

matham commented 4 years ago

I'm not sure what the issue is. But can you try not checking get_mute and instead unconditionally set mute to true and see if it works? Also, try setting the volume to zero and back to 1 if that doesn't work!?

slalomchip commented 4 years ago

I changed the toggleMute() method to ` def toggleMute(self):

    self.player.set_mute(True)`

and it still did not mute.

Then I tried your suggestion to setting the volume to 0 and 1 with this code: ` def toggleMute(self):

    playerVolume = self.player.get_volume()

    print('Volume = ', playerVolume)

    if playerVolume == 0.0:

        self.player.set_volume(1.0)

        print('Should now be unmuted')

    else:

        self.player.set_volume(0.0)

        print('Should now be muted')`

and IT WORKED!

I'll just go with setting volume instead of setting mute. Thanks for the suggestion!

slalomchip commented 4 years ago

Also, please close the issue if you believe the issue is unique to me. Otherwise, it might be something you still want to investigate. Either way s fine with me - I have a solution. Thanks again!

matham commented 4 years ago

I'll leave it open as it's a bug in ffpyplayer and I'll fix it at some point. But basically, https://github.com/matham/ffpyplayer/blob/master/ffpyplayer/player/core.pyx#L1543 needs to check if it's muted, but it doesn't for sdl2.

k8962c commented 2 years ago

I had the same issue, on Windows10, just using ffpyplayer and opencv in a fairly basic script. Works just using the set volume thing; can save/restore the previous volume easy enough also, so not a major issue.

#class or global variable
prevVolume = 1

# in control loop
if player.get_volume() > 0:
    prevVolume = player.get_volume()
    player.set_volume(0)
else:
    player.set_volume(prevVolume)