py2exe (модуль gi не найден) - PullRequest
0 голосов
/ 27 февраля 2020

Я создал приложение для отображения, которое может отображать видеопоток RTSP и HTTP с помощью PyGobjectwin32 pygobjectwin32 , GStreamer 1.16.2, Python 3.4.1 при windows.

Настройка среды для запуска нашего приложения.

  • Установка GStreamer 1.0 из https://gstreamer.freedesktop.org/download и настройка среды:

    GSTREAMER_1_0_ROOT_X86 = Gst 1.0 installation dir like C:\gstreamer\1.0\x86_64\
    
    GST_PLUGIN_PATH_1_0 = %GSTREAMER_1_0_ROOT_X86%\lib\gstreamer-1.0\
    
    Path=%GSTREAMER_1_0_ROOT_X86%\bin;%GSTREAMER_1_0_ROOT_X86%\lib;%Path%
    
  • загрузить pygi-aio-3.10.2-win32_rev14-setup из https://sourceforge.net/projects/pygobjectwin32/files/

  • Установить Pygi-Aio там, где он загружен

  • Включить Gstreamer и плагины в установку.

  • Создать файл gi.pth в местоположении C: \ Python34 \ Lib \ site-packages \, который будет содержать переменную среды gstreamer. Вот так

    %GSTREAMER_1_0_ROOT_X86%\bin  
    %GSTREAMER_1_0_ROOT_X86%\lib
    
  • Запустите файл python final_disp.py через командную строку.

final_disp.py code

import gi 
import sys
from threading import Thread

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

from gi.repository import Gst, Gtk, GLib, GdkX11,GObject, GstVideo

class Main(object):

    def __init__(self):
        Gst.init(sys.argv)
        self.window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
        self.window.set_title("Video-Player")
        self.window.set_default_size(500, 200)
        self.window.connect("destroy", Gtk.main_quit, "WM destroy")
        vbox = Gtk.VBox()
        self.window.add(vbox)
        hbox1 = Gtk.HBox()
        vbox.pack_start(hbox1, True, False,0)
        hbox2 = Gtk.HBox()
        vbox.pack_start(hbox2, True, False,0)
        hbox3 = Gtk.HBox()
        vbox.pack_start(hbox3, True, False,0)

        self.entry1 = Gtk.Entry()
        hbox1.add(self.entry1)
        self.entry2 = Gtk.Entry()
        hbox2.add(self.entry2)
        self.playbtn = Gtk.Button("Play")
        hbox3.add(self.playbtn)
        self.playbtn.connect("clicked", self.start_stop)
        self.window.show_all()

    def start_stop(self, w):
        self.construct()

    def construct(self):
        httpuripath = self.entry1.get_text().strip()
        rtspuripath = self.entry2.get_text().strip()
        if httpuripath == "" or rtspuripath == "":
            msg=Gtk.MessageDialog(self.window,0,Gtk.MessageType.INFO,Gtk.ButtonsType.OK,"Please provide two URL's")
            msg.run()
            msg.destroy()
            return
        else:
            s_one = Player(httpuripath)
            s_two = Player(rtspuripath)
            screen_one=Thread(target= s_one.start).start()
            screen_two=Thread(target= s_two.start).start()


class Player(object):

    def __init__(self,url):

        Gtk.init(sys.argv)
        Gst.init(sys.argv)

        self.state = Gst.State.NULL
        self.duration = Gst.CLOCK_TIME_NONE
        self.playbin = Gst.ElementFactory.make("playbin", "playbin")
        if not self.playbin:
            print("ERROR: Could not create playbin.")
            sys.exit(1)

        self.playbin.set_property("uri", url)

        self.playbin.connect("video-tags-changed", self.on_tags_changed)
        self.playbin.connect("audio-tags-changed", self.on_tags_changed)
        self.playbin.connect("text-tags-changed", self.on_tags_changed)

        self.build_ui()

        bus = self.playbin.get_bus()
        bus.add_signal_watch()
        bus.connect("message::error", self.on_error)
        bus.connect("message::eos", self.on_eos)
        bus.connect("message::state-changed", self.on_state_changed)
        bus.connect("message::application", self.on_application_message)


    def start(self):
        ret = self.playbin.set_state(Gst.State.PLAYING)
        if ret == Gst.StateChangeReturn.FAILURE:
            print("ERROR: Unable to set the pipeline to the playing state")
            sys.exit(1)

        GLib.timeout_add_seconds(1, self.refresh_ui)
        Gtk.main()

        self.cleanup()

    def cleanup(self):
        if self.playbin:
            self.playbin.set_state(Gst.State.NULL)
            self.playbin = None

    def build_ui(self):
        main_window = Gtk.Window.new(Gtk.WindowType.TOPLEVEL)
        main_window.connect("delete-event", self.on_delete_event)

        video_window = Gtk.DrawingArea.new()
        video_window.set_double_buffered(False)
        video_window.connect("realize", self.on_realize)
        video_window.connect("draw", self.on_draw)

        play_button = Gtk.Button.new_from_stock(Gtk.STOCK_MEDIA_PLAY)
        play_button.connect("clicked", self.on_play)

        pause_button = Gtk.Button.new_from_stock(Gtk.STOCK_MEDIA_PAUSE)
        pause_button.connect("clicked", self.on_pause)

        stop_button = Gtk.Button.new_from_stock(Gtk.STOCK_MEDIA_STOP)
        stop_button.connect("clicked", self.on_stop)

        self.slider = Gtk.HScale.new_with_range(0, 100, 1)
        self.slider.set_draw_value(False)
        self.slider_update_signal_id = self.slider.connect(
            "value-changed", self.on_slider_changed)

        self.streams_list = Gtk.TextView.new()
        self.streams_list.set_editable(False)

        controls = Gtk.HBox.new(False, 0)
        controls.pack_start(play_button, False, False, 2)
        controls.pack_start(pause_button, False, False, 2)
        controls.pack_start(stop_button, False, False, 2)
        controls.pack_start(self.slider, True, True, 0)

        main_hbox = Gtk.HBox.new(False, 0)
        main_hbox.pack_start(video_window, True, True, 0)
        main_hbox.pack_start(self.streams_list, False, False, 2)

        main_box = Gtk.VBox.new(False, 0)
        main_box.pack_start(main_hbox, True, True, 0)
        main_box.pack_start(controls, False, False, 0)

        main_window.add(main_box)
        main_window.set_default_size(640, 480)
        main_window.show_all()

    def on_realize(self, widget):
        window = widget.get_window()
        window_handle = window.get_xid()
        self.playbin.set_window_handle(window_handle)

    def on_play(self, button):
        self.playbin.set_state(Gst.State.PLAYING)
        pass

    def on_pause(self, button):
        self.playbin.set_state(Gst.State.PAUSED)
        pass

    def on_stop(self, button):
        self.playbin.set_state(Gst.State.READY)
        pass

    def on_delete_event(self, widget, event):
        self.on_stop(None)
        Gtk.main_quit()

    def on_draw(self, widget, cr):
        if self.state < Gst.State.PAUSED:
            allocation = widget.get_allocation()


        return False

    def on_slider_changed(self, range):
        value = self.slider.get_value()
        self.playbin.seek_simple(Gst.Format.TIME,
                                 Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
                                 value * Gst.SECOND)

    def refresh_ui(self):
        current = -1

        if self.state < Gst.State.PAUSED:
            return True


        if self.duration == Gst.CLOCK_TIME_NONE:
            ret, self.duration = self.playbin.query_duration(Gst.Format.TIME)
            if not ret:
                print("ERROR: Could not query current duration")
            else:

                self.slider.set_range(0, self.duration / Gst.SECOND)

        ret, current = self.playbin.query_position(Gst.Format.TIME)
        if ret:

            self.slider.handler_block(self.slider_update_signal_id)

            self.slider.set_value(current / Gst.SECOND)


            self.slider.handler_unblock(self.slider_update_signal_id)

        return True


    def on_tags_changed(self, playbin, stream):
        self.playbin.post_message(
            Gst.Message.new_application(
                self.playbin,
                Gst.Structure.new_empty("tags-changed")))

    def on_error(self, bus, msg):
        err, dbg = msg.parse_error()
        print("ERROR:", msg.src.get_name(), ":", err.message)
        if dbg:
            print("Debug info:", dbg)

    def on_eos(self, bus, msg):
        print("End-Of-Stream reached")
        self.playbin.set_state(Gst.State.READY)


    def on_state_changed(self, bus, msg):
        old, new, pending = msg.parse_state_changed()
        if not msg.src == self.playbin:
            return

        self.state = new
        print("State changed from {0} to {1}".format(
            Gst.Element.state_get_name(old), Gst.Element.state_get_name(new)))

        if old == Gst.State.READY and new == Gst.State.PAUSED:
            self.refresh_ui()

    def analyze_streams(self):
        buffer = self.streams_list.get_buffer()
        buffer.set_text("")

        nr_video = self.playbin.get_property("n-video")
        nr_audio = self.playbin.get_property("n-audio")
        nr_text = self.playbin.get_property("n-text")

        for i in range(nr_video):
            tags = None
            tags = self.playbin.emit("get-video-tags", i)
            if tags:
                buffer.insert_at_cursor("video stream {0}\n".format(i))
                _, str = tags.get_string(Gst.TAG_VIDEO_CODEC)
                buffer.insert_at_cursor(
                    "  codec: {0}\n".format(
                        str or "unknown"))

        for i in range(nr_audio):
            tags = None
            tags = self.playbin.emit("get-audio-tags", i)
            if tags:
                buffer.insert_at_cursor("\naudio stream {0}\n".format(i))
                ret, str = tags.get_string(Gst.TAG_AUDIO_CODEC)
                if ret:
                    buffer.insert_at_cursor(
                        "  codec: {0}\n".format(
                            str or "unknown"))

                ret, str = tags.get_string(Gst.TAG_LANGUAGE_CODE)
                if ret:
                    buffer.insert_at_cursor(
                        "  language: {0}\n".format(
                            str or "unknown"))

                ret, str = tags.get_uint(Gst.TAG_BITRATE)
                if ret:
                    buffer.insert_at_cursor(
                        "  bitrate: {0}\n".format(
                            str or "unknown"))

        for i in range(nr_text):
            tags = None

            tags = self.playbin.emit("get-text-tags", i)
            if tags:
                buffer.insert_at_cursor("\nsubtitle stream {0}\n".format(i))
                ret, str = tags.get_string(Gst.TAG_LANGUAGE_CODE)
                if ret:
                    buffer.insert_at_cursor(
                        "  language: {0}\n".format(
                            str or "unknown"))

    def on_application_message(self, bus, msg):
        if msg.get_structure().get_name() == "tags-changed":
            self.analyze_streams()      




GObject.threads_init()
obj=Main()
Gtk.main()

файл setup.py для создания exe-файла с использованием py2xe

from distutils.core import setup 

import distutils.sysconfig

import py2exe 

setup(console=['final_disp.py'])

запуска setup.py через командную строку python setup.py p2exe

пока все здесь работает нормально. но когда я успешно создал exe-файл, он показывает, что gi moudle не найден, как

ошибка после запуска build exe

ошибка при создании exe

Есть ли способ указать путь к библиотекам gstreamer для его создания из exe. потому что для запуска кода у меня есть файл gi.pth, который сообщает python, что здесь указан путь к библиотеке gstreamer, он соблюдается и успешно выполняется. но когда я пытаюсь сделать exe из него, он показывает сообщение об ошибке "gi module not found".

...