2016-10-17 1 views
5

J'ai créé un lecteur vidéo dans Gtk3 en utilisant Gstreamer dans Python3. Cela fonctionne sauf quand j'ajoute un GtkMenuBar (place 2). Il affichera alors un écran noir, ou échouera avec une exception. L'exception fait référence au XInitThreads, que j'appelle (Place 1) (j'ai pris cela du projet pitivi) mais cela ne semble pas faire de différence.Lecture d'une vidéo dans Gtk dans une fenêtre avec une barre de menus

Question: Comment est-ce que je fais ce travail?

Autres choses que je voudrais savoir:

  1. Pourquoi la barre de menus romprait ce?
  2. Cela va clairement se briser sur tout ce qui n'est pas X, y a-t-il un composant prédéfini à l'abstraction de cette logique et est-ce qu'il y a une plateforme croisée qui me manque?

System:

  • python3
  • gtk3
  • Ubuntu 16,04

L'exception:

[xcb] Unknown request in queue while dequeuing 
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called 
[xcb] Aborting, sorry about that. 
python3: ../../src/xcb_io.c:179: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed. 

Le code (en tant que petite une forme aussi pos sible de démontrer le concept):

import gi 
gi.require_version('Gtk', '3.0') 
gi.require_version('Gst', '1.0') 
gi.require_version('GstVideo', '1.0') 

from gi.repository import Gtk, xlib 
from gi.repository import Gst, Gdk, GdkX11, GstVideo 
Gst.init(None) 
Gst.init_check(None) 

# Place 1 
from ctypes import cdll 
x11 = cdll.LoadLibrary('libX11.so') 
x11.XInitThreads() 

# [xcb] Unknown request in queue while dequeuing 
# [xcb] Most likely this is a multi-threaded client and XInitThreads has not been called 
# [xcb] Aborting, sorry about that. 
# python3: ../../src/xcb_io.c:179: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed. 

# (foo.py:31933): Gdk-WARNING **: foo.py: Fatal IO error 11 (Resource temporarily unavailable) on X server :1. 

class PipelineManager(object): 
    def __init__(self, window, pipeline): 
     self.window = window 
     if isinstance(pipeline, str): 
      pipeline = Gst.parse_launch(pipeline) 

     self.pipeline = pipeline 

     bus = pipeline.get_bus() 
     bus.set_sync_handler(self.bus_callback) 
     pipeline.set_state(Gst.State.PLAYING) 

    def bus_callback(self, bus, message): 
     if message.type is Gst.MessageType.ELEMENT: 
      if GstVideo.is_video_overlay_prepare_window_handle_message(message): 
       Gdk.threads_enter() 
       Gdk.Display.get_default().sync() 
       win = self.window.get_property('window') 

       if isinstance(win, GdkX11.X11Window): 
        message.src.set_window_handle(win.get_xid()) 
       else: 
        print('Nope') 

       Gdk.threads_leave() 
     return Gst.BusSyncReply.PASS 


pipeline = Gst.parse_launch('videotestsrc ! xvimagesink sync=false') 

window = Gtk.ApplicationWindow() 

header_bar = Gtk.HeaderBar() 
header_bar.set_show_close_button(True) 
# window.set_titlebar(header_bar) # Place 2 

drawing_area = Gtk.DrawingArea() 
drawing_area.connect('realize', lambda widget: PipelineManager(widget, pipeline)) 
window.add(drawing_area) 

window.show_all() 

def on_destroy(win): 
    try: 
     Gtk.main_quit() 
    except KeyboardInterrupt: 
     pass 

window.connect('destroy', on_destroy) 

Gtk.main() 
+1

Je ne peux pas répondre à la question, mais cela est une question superbe. Sur le sujet, un problème spécifique, pas quelque chose de simple dans la documentation, fournit un MCVE parfait, affiche un message d'erreur, des informations système, le but du code, etc. Cela devrait être un exemple de la façon de poser une question. – oldtechaa

Répondre

2

Lors de la recherche par le biais de la documentation sur une autre question, je suis tombé sur une référence au widget gtksink. Cela semble être la bonne façon de mettre la vidéo dans une fenêtre gtk, mais malheureusement, aucun des tutoriels sur cette utilisation. L'utilisation du widget gtksink résout tous les problèmes et réduit considérablement la complexité du code.

Le code révisé:

from pprint import pprint 

import gi 
gi.require_version('Gtk', '3.0') 
gi.require_version('Gst', '1.0') 
gi.require_version('GstVideo', '1.0') 

from gi.repository import Gtk, Gst 
Gst.init(None) 
Gst.init_check(None) 


class GstWidget(Gtk.Box): 
    def __init__(self, pipeline): 
     super().__init__() 
     self.connect('realize', self._on_realize) 
     self._bin = Gst.parse_bin_from_description('videotestsrc', True) 

    def _on_realize(self, widget): 
     pipeline = Gst.Pipeline() 
     factory = pipeline.get_factory() 
     gtksink = factory.make('gtksink') 
     pipeline.add(gtksink) 
     pipeline.add(self._bin) 
     self._bin.link(gtksink) 
     self.pack_start(gtksink.props.widget, True, True, 0) 
     gtksink.props.widget.show() 
     pipeline.set_state(Gst.State.PLAYING) 


window = Gtk.ApplicationWindow() 

header_bar = Gtk.HeaderBar() 
header_bar.set_show_close_button(True) 
window.set_titlebar(header_bar) # Place 2 

widget = GstWidget('videotestsrc') 
widget.set_size_request(200, 200) 

window.add(widget) 

window.show_all() 

def on_destroy(win): 
    try: 
     Gtk.main_quit() 
    except KeyboardInterrupt: 
     pass 

window.connect('destroy', on_destroy) 

Gtk.main()