Ejemplo n.º 1
0
class WindowServiceProxy(object):
    def __init__(self, port=8080, force_aspect_ratio=False):
        global override_methods

        print '[WindowServiceProxy] force_aspect_ratio={}'.format(force_aspect_ratio)
        self._force_aspect_ratio = force_aspect_ratio
        self._port = port
        self._override_methods = override_methods
        self._server_process = server_popen(port,
                force_aspect_ratio=force_aspect_ratio)
        self._ctx = zmq.Context.instance()
        self._sock = SerializingSocket(self._ctx, zmq.REQ)
        self._sock.connect('tcp://localhost:%d' % port)
        self._initialized = True
        self._methods = set(['get_available_commands'])
        self._methods = self._methods.union(set(self.get_available_commands()))

    def __getattr__(self, attr):
        if attr in self._methods and attr not in self._override_methods:
            return DeferredCommand(attr, self._sock)
        else:
            return object.__getattribute__(self, attr)

    @property
    def port(self):
        return self._port

    @property
    def pids(self):
        return tuple(self._pids)

    def add_pid(self, pid):
        if pid not in self.pids:
            self._pids.append(pid)

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        self.close()

    def __del__(self):
        self.close()

    def close(self):
        if self._initialized:
            try:
                child_joined = False
                self._sock.send_zipped_pickle({'command': 'join'})
                for i in range(5):
                    if self._sock.poll(50):
                        self._sock.recv_zipped_pickle()
                        child_joined = True
            finally:
                if not child_joined:
                    self._server_process.terminate()
                self._initialized = False
Ejemplo n.º 2
0
    def __init__(self, port=8080, force_aspect_ratio=False):
        global override_methods

        print '[WindowServiceProxy] force_aspect_ratio={}'.format(force_aspect_ratio)
        self._force_aspect_ratio = force_aspect_ratio
        self._port = port
        self._override_methods = override_methods
        self._server_process = server_popen(port,
                force_aspect_ratio=force_aspect_ratio)
        self._ctx = zmq.Context.instance()
        self._sock = SerializingSocket(self._ctx, zmq.REQ)
        self._sock.connect('tcp://localhost:%d' % port)
        self._initialized = True
        self._methods = set(['get_available_commands'])
        self._methods = self._methods.union(set(self.get_available_commands()))
Ejemplo n.º 3
0
    def run(self):
        '''
        Method to be run in the child process.
        '''
        import zmq
        from serialsocket import SerializingSocket

        self.ctx = zmq.Context.instance()
        self.sock = SerializingSocket(self.ctx, zmq.REP)
        if self.port is None:
            self.port = self.sock.bind_to_random_port('tcp://*')
        else:
            self.sock.bind('tcp://*:%d' % self.port)
        print 'socket bound to port %d' % self.port
        self.child_pipe.send(self.port)

        self.pm = PipelineManager(force_aspect_ratio=self.force_aspect_ratio)
        self.pm.window_xid = self.window_xid

        update_period_ms = 10
        print 'using update period of %d ms' % update_period_ms
        gtk.timeout_add(update_period_ms, self._update_state)
        gtk.main()
Ejemplo n.º 4
0
class WindowProcess(Process):
    def __init__(self, window_xid, port=None, force_aspect_ratio=True):
        super(WindowProcess, self).__init__()
        self.force_aspect_ratio = force_aspect_ratio
        self.parent_pipe, self.child_pipe = Pipe()
        self.window_xid = window_xid
        self.pm = None
        self.last_frame = None
        self.port = port

    def run(self):
        '''
        Method to be run in the child process.
        '''
        import zmq
        from serialsocket import SerializingSocket

        self.ctx = zmq.Context.instance()
        self.sock = SerializingSocket(self.ctx, zmq.REP)
        if self.port is None:
            self.port = self.sock.bind_to_random_port('tcp://*')
        else:
            self.sock.bind('tcp://*:%d' % self.port)
        print 'socket bound to port %d' % self.port
        self.child_pipe.send(self.port)

        self.pm = PipelineManager(force_aspect_ratio=self.force_aspect_ratio)
        self.pm.window_xid = self.window_xid

        update_period_ms = 10
        print 'using update period of %d ms' % update_period_ms
        gtk.timeout_add(update_period_ms, self._update_state)
        gtk.main()

    def _update_state(self):
        '''
        This method will be called at regular intervals to handle any
        pending requests in the pipe.
        '''
        while self.sock.poll(timeout=10):
            request = self.sock.recv_zipped_pickle()
            try:
                threads_entered = False
                gtk.threads_enter()
                threads_entered = True
                response = self._process_request(request)
                self.sock.send_zipped_pickle(response)
            finally:
                if threads_entered:
                    gtk.threads_leave()
        return True

    def _process_request(self, request):
        '''
        Execute the specified command by looking up the corresponding
        member function.
        '''
        command_attr = '_command___%s' % request.get('command', None)
        if hasattr(self, command_attr):
            return getattr(self, command_attr)(*request.get('args', []),
                                               **request.get('kwargs', {}))
        else:
            logging.warning('Invalid command: %s' % request.get('command',
                                                                None))
            return None

    ### command-processing methods ####################################################

    def _command___get_available_commands(self):
        command_prefix = '_command___'
        return [k[len(command_prefix):] for k in dir(self)
                if k.startswith(command_prefix)]

    def _command___window_xid(self, window_xid):
        if window_xid is not None:
            self.pm.window_xid = window_xid
        return self.pm.window_xid

    def _command___start(self):
        # Cast GStreamer state-change return value _(i.e.,
        # `GstStateChangeReturn`)_ enumerated type as integer.  Otherwise,
        # there can be issues when calling through a proxy.
        #
        # For example, when running the [MicroDrop][1] application by calling
        # `python -m microdrop.microdrop` from outside of the source directory,
        # the following error occurs when calling one of the remote API
        # commands:
        #
        #     Traceback (most recent call last):
        #       File ".../microdrop/gui/dmf_device_view.py", line 266, in destroy_video_proxy
        #         self._proxy.stop()
        #       File ".../pygst-utils/pygst_utils/video_pipeline/window_service_proxy.py", line 40, in __call__
        #         return self.sock.recv_zipped_pickle()
        #       File ".../pygst-utils/pygst_utils/video_pipeline/serialsocket.py", line 31, in recv_zipped_pickle
        #         return pickle.loads(pobj)
        #     AttributeError: 'NoneType' object has no attribute 'StateChangeReturn'
        #
        # [1]: http://microfluidics.utoronto.ca/microdrop
        return int(self.pm.pipeline.set_state(gst.STATE_PLAYING))

    def _command___pipeline_available(self):
        return not (self.pm.pipeline is None)

    def _command___get_pid(self):
        return os.getpid()

    def _command___get_state(self):
        # Cast GStreamer state-change return value _(i.e.,
        # `GstStateChangeReturn`)_ enumerated type as integer.  Otherwise,
        # there can be issues when calling through a proxy.
        # See `_command___start` for more details
        return int(self.pm.pipeline.get_state(gst.STATE_NULL))

    def _command___get_video_mode_enum(self):
        from ..video_mode import get_video_mode_enum

        return get_video_mode_enum()

    def _command___get_video_mode_map(self):
        from ..video_mode import get_video_mode_map

        try:
            result = get_video_mode_map()
        except DeviceNotFound:
            result = {}
        return result

    def _command___select_video_mode(self):
        from ..video_mode import select_video_mode

        return select_video_mode()

    def _command___select_video_caps(self):
        from ..video_mode import select_video_caps

        device, caps_str = select_video_caps()
        return {'device': str(device), 'caps_str': caps_str}

    def _command___get_available_video_modes(self):
        from ..video_mode import get_available_video_modes

        return get_available_video_modes()

    def _command___get_video_source_configs(self):
        from ..video_mode import get_video_source_configs

        return get_video_source_configs()

    def _command___stop(self):
        response = self.pm.pipeline.set_state(gst.STATE_NULL)
        # Cast GStreamer state-change return value _(i.e.,
        # `GstStateChangeReturn`)_ enumerated type as integer.  Otherwise,
        # there can be issues when calling through a proxy.
        # See `_command___start` for more details
        return int(response)

    def _command___request_frame(self):
        frame_grabber = self.pm.pipeline.get_by_name('grab_frame')
        if frame_grabber:
            frame_grabber.set_property('grab-requested', True)

    def _command___set_draw_queue(self, draw_queue):
        cairo_draw = self.pm.pipeline.get_by_name('cairo_draw')
        if cairo_draw:
            cairo_draw.set_property('draw-queue', pickle.dumps(draw_queue))

    def _command___set_warp_transform(self, transform_str):
        warp_bin = self.pm.pipeline.get_by_name('warp_bin')
        if warp_bin:
            warp_bin.warper.set_property('transform-matrix', transform_str)

    def _command___scale(self, width, height):
        if width is None or height is None:
            return None
        caps_filter = self.pm.pipeline.get_by_name('video_scale_caps_filter')
        if not caps_filter:
            return None
        caps_str = 'video/x-raw-yuv,width={},height={}'.format(width, height)
        caps = gst.Caps(caps_str)
        caps_filter.set_property('caps', caps)
        print '[_scale] width={} height={} DONE'.format(width, height)

    def _command___join(self):
        gtk.main_quit()
        return False

    def _command___pop_frame(self):
        frame = self.last_frame
        self.last_frame = None
        return frame

    def _command___get_frame(self):
        return self.last_frame

    def _command___create(self, device, caps_str, record_path=None,
                          bitrate=None, draw_queue=None, with_scale=False,
                          with_warp=False, with_frame_grab=True):
        from ..video_mode import create_video_source

        def init_pipeline(pm, device, caps_str, bitrate, record_path,
                          draw_queue, with_scale, with_warp, with_frame_grab):
            values = [device, caps_str, bitrate, record_path, draw_queue,
                      with_scale, with_warp, with_frame_grab]
            print 'init_pipeline args={}'.format(values)
            video_source = create_video_source(device, caps_str)
            if with_frame_grab:
                on_frame_grabbed = self.on_frame_grabbed
            else:
                on_frame_grabbed = None
            pipeline = get_pipeline(video_source, bitrate, record_path,
                                    draw_queue, with_scale=with_scale,
                                    with_warp=with_warp,
                                    on_frame_grabbed=on_frame_grabbed)
            pm.pipeline = pipeline
            return pm.pipeline.set_state(gst.STATE_READY)

        response = init_pipeline(self.pm, device, caps_str, bitrate,
                                 record_path, draw_queue, with_scale,
                                 with_warp, with_frame_grab)
        # Cast GStreamer state-change return value _(i.e.,
        # `GstStateChangeReturn`)_ enumerated type as integer.  Otherwise,
        # there can be issues when calling through a proxy.
        # See `_command___start` for more details
        return int(response)

    ### utility methods ####################################################

    def on_frame_grabbed(self, frame):
        self.last_frame = frame
Ejemplo n.º 5
0
    ### utility methods ####################################################

    def on_frame_grabbed(self, frame):
        self.last_frame = frame


if __name__ == '__main__':
    import multiprocessing

    multiprocessing.freeze_support()

    p = WindowProcess(0, 8888)
    p.start()
    port = p.parent_pipe.recv()
    print 'Received port {} from child process'.format(port)

    import zmq
    from serialsocket import SerializingSocket

    ctx = zmq.Context.instance()
    req = SerializingSocket(ctx, zmq.REQ)
    req.connect('tcp://localhost:%d' % port)
    req.send_zipped_pickle({'command': 'select_video_mode'})
    response = req.recv_zipped_pickle()
    print response
    try:
        p.join()
    except:
        p.terminate()