libvlc 和 dbus 接口

Posted

技术标签:

【中文标题】libvlc 和 dbus 接口【英文标题】:libvlc and dbus interface 【发布时间】:2012-11-13 02:37:28 【问题描述】:

我正在尝试使用 libvlc 创建一个基本的媒体播放器,该播放器将通过 dbus 进行控制。我正在为 python 使用 gtk 和 libvlc 绑定。代码基于vlc website的官方示例

我唯一修改的是将dbus接口添加到vlc实例中

# Create a single vlc.Instance() to be shared by (possible) multiple players.
instance = vlc.Instance()
print vlc.libvlc_add_intf(instance, "dbus"); // this is what i added. // returns 0 which is ok

一切都很好,该演示可以运行并播放任何视频文件。但由于某种原因,dbus 控制模块不起作用(我不敢相信我刚才说了可怕的“不起作用”的话):

我已经有了绑定到 MPRIS 2 接口的工作客户端 dbus 代码。我可以控制一个普通的 VLC 媒体播放器实例——它工作得很好,但是上面的例子没有任何反应。 dbus 控制模块已正确加载,因为libvlc_add_intf 没有返回错误,我可以在 D-Feet (org.mpris.MediaPlayer2.vlc) 中看到 MPRIS 2 服务。 即使在 D-Feet 中,尝试调用 dbus vlc 对象的任何方法都不会返回错误,但没有任何反应。

我是否需要配置其他东西才能让 dbus 模块控制 libvlc 播放器?

谢谢

更新

似乎创建 vlc 实例并设置更高的详细程度表明收到了 DBus 调用,但它们对播放器本身没有任何影响。 此外,将 RC 接口添加到实例而不是 DBus 也有一些问题:当我从命令行运行示例时,它会将我带到 RC 接口控制台,我可以在其中键入控制命令,但它的行为与DBus - 没有任何反应,没有错误,nada,绝对没有。它完全忽略命令。

有什么想法吗?

更新 2

这是使用 libvlc 创建基本播放器的代码:

    from    dbus.mainloop.glib import DBusGMainLoop
    import gtk
    import  gobject


    import sys
    import vlc

    from gettext import gettext as _


    # Create a single vlc.Instance() to be shared by (possible) multiple players.
    instance = vlc.Instance("--one-instance --verbose 2")

    class VLCWidget(gtk.DrawingArea):
        """Simple VLC widget.

        Its player can be controlled through the 'player' attribute, which
        is a vlc.MediaPlayer() instance.
        """
        def __init__(self, *p):
            gtk.DrawingArea.__init__(self)
            self.player = instance.media_player_new()
            def handle_embed(*args):
                if sys.platform == 'win32':
                    self.player.set_hwnd(self.window.handle)
                else:
                    self.player.set_xwindow(self.window.xid)
                return True
            self.connect("map", handle_embed)
            self.set_size_request(640, 480)

    class VideoPlayer:
        """Example simple video player.
        """
        def __init__(self):
            self.vlc = VLCWidget()

        def main(self, fname):
            self.vlc.player.set_media(instance.media_new(fname))
            w = gtk.Window()
            w.add(self.vlc)
            w.show_all()
            w.connect("destroy", gtk.main_quit)
            self.vlc.player.play()
            DBusGMainLoop(set_as_default = True)
            gtk.gdk.threads_init()
            gobject.MainLoop().run()


    if __name__ == '__main__':
        if not sys.argv[1:]:
           print "You must provide at least 1 movie filename"
           sys.exit(1)
        if len(sys.argv[1:]) == 1:
            # Only 1 file. Simple interface
            p=VideoPlayer()
            p.main(sys.argv[1])

脚本可以从命令行运行,例如:

python example_vlc.py file.avi

连接到 vlc dbus 对象的客户端代码太长而无法发布,因此请假装我正在使用D-Feet 来获取总线连接并向其发布消息。 示例运行后,我可以在 d-feet 中看到播放器 dbus 接口,但我无法控制它。 我还应该在上面的代码中添加什么以使其正常工作吗?

【问题讨论】:

@mattn 查看更新后的问题。 你成功了吗? @Guillaume 很遗憾没有:( 问题可能是 gtk/vlc 代码正在吃事件。尝试通过多处理将 dbus 放入子进程中,并通过队列与其通信。这样您就可以确保这两个部分使用单独的进程空间和事件。 【参考方案1】:

我看不到您的事件循环实现,因此很难判断是什么原因导致命令无法被识别或被丢弃。您的线程是否有可能丢失了堆栈跟踪信息并实际上引发了异常?

如果您添加事件循环和 DBus 命令解析的伪代码版本或简化版本,您可能会收到更多响应?

【讨论】:

【参考方案2】:

在 nullege.com 上找到的工作程序使用 ctypes。充当服务器的一个使用 rpyc。忽略那个。

ctypes 相对于 dbus 的优势在于巨大的速度优势(调用 C 库代码,不使用 python 进行交互)以及不需要库来实现 dbus 接口。

没有找到任何使用 gtk 或 dbus 的示例;-(

值得注意的例子

PyNuvo vlc.py

Milonga Tango DJing program

使用 dbus / gtk

dbus 使用 gobject 主循环,而不是 gtk 主循环。完全不同的野兽。不要越过溪流!一些修复:

不需要这个。线程是邪恶的。

gtk.gdk.threads_init()

gtk.main_quit() 在使用 gobject Mainloop 时不应该工作。 gobject mainloop 不能存在于你的类中。

if __name__ == '__main__':
loop = gobject.MainLoop()
loop.run()

loop 传入你的类。然后调用退出应用

loop.quit()

dbus(通知)/gtk 工作示例

不会为你编写你的 vlc 应用程序。但这是一个使用 dbus / gtk 的工作示例。只要适应vlc。假设你接受了我对上面 gtk 的建议。如您所知,在使用 gobject.Mainloop 时必须调用 DesktopNotify 的任何实例。但是你可以把它放在你的主类中的任何地方。

desktop_notify.py

from __future__ import print_function
import gobject
import time, dbus
from dbus.exceptions import DBusException
from dbus.mainloop.glib import DBusGMainLoop

class DesktopNotify(object):
    """ Notify-OSD ubuntu's implementation has a 20 message limit. U've been warned. When queue is full, delete old message before adding new messages."""
    #Static variables
    dbus_loop = None
    dbus_proxy = None
    dbus_interface = None
    loop = None

    @property
    def dbus_name(self):
        return ("org.freedesktop.Notifications")

    @property
    def dbus_path(self):
        return ("/org/freedesktop/Notifications")

    @property
    def dbus_interface(self):
        return self.dbus_name

    def __init__(self, strInit="initializing passive notification messaging")
        strProxyInterface = "<class 'dbus.proxies.Interface'>"
        """ Reinitializing dbus when making a 2nd class instance would be bad"""
        if str(type(DesktopNotify.dbus_interface)) != strProxyInterface:
            DesktopNotify.dbus_loop = DBusGMainLoop(set_as_default=True)
            bus = dbus.SessionBus(mainloop=DesktopNotify.dbus_loop)
            DesktopNotify.dbus_proxy = bus.get_object(self.dbus_name, self.dbus_path)
            DesktopNotify.dbus_interface = dbus.Interface(DesktopNotify.dbus_proxy, self.dbus_interface )
            DesktopNotify.dbus_proxy.connect_to_signal("NotificationClosed", self.handle_closed)

    def handle_closed(self, *arg, **kwargs):
        """ Notification closed by user or by code. Print message or not"""
        lngNotificationId = int(arg[0])
        lngReason = int(arg[1])

    def pop(self, lngID):
        """ ID stored in database, but i'm going to skip this and keep it simple"""
        try:
            DesktopNotify.dbus_interface.CloseNotification(lngID)
        except DBusException as why:
            print(self.__class__.__name__ + ".pop probably no message with id, lngID, why)
        finally:
            pass

    def push(self, strMsgTitle, strMsg, dictField):
        """ Create a new passive notification (took out retrying and handling full queues)"""
        now = time.localtime( time.time() )
        strMsgTime = strMsg + " " + time.asctime(now)
        del now
        strMsgTime = strMsgTime % dictField

        app_name="[your app name]"
        app_icon = ''
        actions = ''
        hint = ''
        expire_timeout = 10000 #Use seconds * 1000
        summary = strMsgTitle
        body = strMsgTime
        lngNotificationID = None
        try:
            lngNotificationID = DesktopNotify.dbus_interfacec.Notify(app_name, 0, app_icon, summary, body, actions, hint, expire_timeout)
        except DBusException as why:
            #Excellent spot to delete oldest notification and then retry
            print(self.__class__.__name__ + ".push Being lazy. Posting passive notification was unsuccessful.", why)
        finally:
            #Excellent spot to add to database upon success
            pass

【讨论】:

以上是关于libvlc 和 dbus 接口的主要内容,如果未能解决你的问题,请参考以下文章

Linux 下eclipse cpp配置libvlc环境

FileNotFoundError:找不到模块“libvlc.dll”

C++ LibVLC 从帧/图像创建流

libVLC 添加图片和文本水印

libvlc播放m3u8流 无法获得视频长度问题[记录]

应该向哪个项目添加 LibVLC 依赖项?