コード例 #1
0
ファイル: player.py プロジェクト: clones/kaa
 def _child_spawn(self):
     # Launch self (-u is unbuffered stdout)
     script = os.path.join(os.path.dirname(__file__), 'main.py')
     # Put this into ChildProcess to enable gdb traces. It is deactivated
     # as default because it messes up kaa shutdown handling.
     # gdb = log.getEffectiveLevel() == logging.DEBUG
     self._xine = ChildProcess(self, script, gdb=False)
     self._xine.stop_command = kaa.WeakCallable(self._xine.die)
     signal = self._xine.start(str(self._osd_shmkey))
     signal.connect_weak(self._child_exited)
     self._xine_configured = False
コード例 #2
0
ファイル: player.py プロジェクト: clones/kaa
 def open(self, media):
     """
     Open media.
     """
     self._mrl = media.url
     if not self._gst:
         script = os.path.join(os.path.dirname(__file__), 'main.py')
         self._gst = ChildProcess(self, script)
         self._gst.set_stop_command(WeakCallable(self._gst.die))
         self._gst.start().connect_weak(self._child_exited)
     self.position = 0.0
     self.state = STATE_OPENING
     self._gst.open(self._mrl)
     if self._window:
         aspect, size = self.aspect
         self._gst.configure_video('xv', window=self._window.get_id(),
                                   aspect=aspect, size=size)
     else:
         self._gst.configure_video('none')
     self._gst.configure_audio(config.audio.driver)
コード例 #3
0
ファイル: player.py プロジェクト: clones/kaa
class GStreamer(MediaPlayer):

    def __init__(self, properties):
        super(GStreamer, self).__init__(properties)
        self.state = STATE_NOT_RUNNING
        self._gst = None


    def _child_exited(self, exitcode):
        self.state = STATE_NOT_RUNNING
        self._gst = None


    # public API

    def open(self, media):
        """
        Open media.
        """
        self._mrl = media.url
        if not self._gst:
            script = os.path.join(os.path.dirname(__file__), 'main.py')
            self._gst = ChildProcess(self, script)
            self._gst.set_stop_command(WeakCallable(self._gst.die))
            self._gst.start().connect_weak(self._child_exited)
        self.position = 0.0
        self.state = STATE_OPENING
        self._gst.open(self._mrl)
        if self._window:
            aspect, size = self.aspect
            self._gst.configure_video('xv', window=self._window.get_id(),
                                      aspect=aspect, size=size)
        else:
            self._gst.configure_video('none')
        self._gst.configure_audio(config.audio.driver)


    def play(self):
        """
        Start playback.
        """
        self._gst.play()


    def stop(self):
        """
        Stop playback.
        """
        self.state = STATE_STOPPING
        self._gst.stop()


    def pause(self):
        """
        Pause playback.
        """
        self._gst.pause()
        self.state = STATE_PAUSED


    def resume(self):
        """
        Resume playback.
        """
        self._gst.play()
        self.state = STATE_PLAYING


    def release(self):
        """
        Release audio and video devices.
        """
        if self._gst:
            self.state = STATE_SHUTDOWN
            self._gst.die()


    def seek(self, value, type):
        """
        SEEK_RELATIVE, SEEK_ABSOLUTE or SEEK_PERCENTAGE.
        """
        self._gst.seek(value, type)


    @runtime_policy(DEFER_UNTIL_PLAYING)
    def _set_prop_audio_delay(self, delay):
        """
        Sets audio delay. Positive value defers audio by delay.
        """
        self._gst.set_audio_delay(delay)
コード例 #4
0
ファイル: player.py プロジェクト: clones/kaa
class Xine(MediaPlayer):

    def __init__(self, properties):
        super(Xine, self).__init__(properties)
        self._is_in_menu = False
        self._cur_frame_output_mode = [True, False, None] # vo, shmem, size
        self._locked_buffer_offsets = []
        self._child_spawn()


    #
    # child handling
    #

    def _child_spawn(self):
        # Launch self (-u is unbuffered stdout)
        script = os.path.join(os.path.dirname(__file__), 'main.py')
        # Put this into ChildProcess to enable gdb traces. It is deactivated
        # as default because it messes up kaa shutdown handling.
        # gdb = log.getEffectiveLevel() == logging.DEBUG
        self._xine = ChildProcess(self, script, gdb=False)
        self._xine.stop_command = kaa.WeakCallable(self._xine.die)
        signal = self._xine.start(str(self._osd_shmkey))
        signal.connect_weak(self._child_exited)
        self._xine_configured = False


    def _child_exited(self, exitcode):
        log.debug('xine child dead')
        self._xine = None
        if self._window:
            # Disconnect signals from existing window.
            disconnect = self._window.signals.disconnect
            disconnect('configure_event', self._window_configure_event)
            disconnect('map_event', self._window_visibility_event)
            disconnect('unmap_event', self._window_visibility_event)
            disconnect('expose_event', self._window_expose_event)

        # remove shared memory
        if self._osd_shmem:
            try:
                self._osd_shmem.detach()
                kaa.shm.remove_memory(self._osd_shmem.shmid)
            except kaa.shm.error:
                # Probably already deleted by child
                pass
            self._osd_shmem = None

        if self._frame_shmem:
            try:
                self._frame_shmem.detach()
            except kaa.shm.error:
                pass
            self._frame_shmem = None
        self.state = STATE_NOT_RUNNING


    #
    # Commands from child
    #

    def _child_set_status(self, pos, time, length, status, speed):
        old_pos = self.position
        if self.state in (STATE_PAUSED, STATE_PLAYING, STATE_OPEN) and time is not None:
            self.position = float(time)
        if length is not None:
            self.streaminfo["length"] = length

        if status == 2:
            if self.state in (STATE_STOPPING, STATE_SHUTDOWN):
                # ignore the status update, we are stopping the player
                return
            if self.state not in (STATE_PAUSED, STATE_PLAYING):
                self.state = STATE_PLAYING
            if speed == XINE_SPEED_PAUSE and self.state != STATE_PAUSED:
                self.state = STATE_PAUSED
            elif speed > XINE_SPEED_PAUSE and self.state != STATE_PLAYING:
                prev_state = self.state
                self.state = STATE_PLAYING
            # TODO:
            # if self.position - old_pos < 0 or self.position - old_pos > 1:
            # self.signals["seek"].emit(self.position)
        elif status in (0, 1):
            if self.state in (STATE_PAUSED, STATE_PLAYING):
                # Stream ended.
                log.debug('xine stream ended')
                self.state = STATE_IDLE


    def _child_osd_configure(self, width, height, aspect):
        if not self._osd_shmem:
            shmid = kaa.shm.getshmid(self._osd_shmkey)
            if shmid:
                self._osd_shmem = kaa.shm.memory(shmid)
                self._osd_shmem.attach()

        # TODO: remember these values and emit them to new connections to
        # this signal after this point.
        self.signals["osd_configure"].emit(width, height, self._osd_shmem.addr + 16, width, height)


    def _child_resize(self, size):
        pass
        #self._window.resize(size)


    def _child_set_streaminfo(self, status, info):
        if not status:
            # failed playback
            self.state = STATE_IDLE
            return

        changed = info != self.streaminfo
        self.streaminfo = info

        if self.state == STATE_OPENING:
            self.state = STATE_OPEN

        if changed:
            self.signals["stream_changed"].emit()

    def _child_frame_reconfigure(self, width, height, aspect):
        si = self.streaminfo.copy()
        si.update({
            'width': width,
            'height': height,
            'aspect': aspect
        })
        self._child_set_streaminfo(True, si)

    def _child_xine_event(self, event, data):
        if event == XINE_EVENT_UI_NUM_BUTTONS:
            self._is_in_menu = data["num_buttons"] > 0


    def _child_play_stopped(self):
        log.debug('xine stopped')
        if not self.state in (STATE_NOT_RUNNING, STATE_SHUTDOWN):
            self.state = STATE_IDLE


    def _child_frame_notify(self, shmid, offset):
        if not self._frame_shmem or shmid != self._frame_shmem.shmid:
            if self._frame_shmem:
                self._frame_shmem.detach()
            self._frame_shmem = kaa.shm.memory(shmid)
            self._frame_shmem.attach()

        try:
            lock, width, height, aspect = struct.unpack("bhhd", self._frame_shmem.read(16, offset))
        except kaa.shm.error:
            self._frame_shmem.detach()
            self._frame_shmem = None
            return

        if width > 0 and height > 0 and aspect > 0:
            self._locked_buffer_offsets.append(offset)
            a = self._frame_shmem.addr + 32 + offset
            self.signals["frame"].emit(width, height, aspect, a, "yv12")

    #
    # Window handling
    #

    def _window_visibility_event(self):
        self._xine.window_changed(self._window.get_id(), self._window.get_size(),
                                  self._window.get_visible(), [])

    def _window_expose_event(self, regions):
        self._xine.window_changed(self._window.get_id(), self._window.get_size(),
                                  self._window.get_visible(), regions)

    def _window_configure_event(self, pos, size):
        self._xine.window_changed(self._window.get_id(), size,
                                  self._window.get_visible(), [])

    def set_window(self, window):
        """
        Set a window for the player (override from MediaPlayer)
        """
        old_window = self._window
        super(Xine, self).set_window(window)

        if old_window and old_window != self._window:
            # Disconnect signals from existing window.
            old_window.signals["configure_event"].disconnect(self._window_configure_event)
            old_window.signals["map_event"].disconnect(self._window_visibility_event)
            old_window.signals["unmap_event"].disconnect(self._window_visibility_event)
            old_window.signals["expose_event"].disconnect(self._window_expose_event)

        if window and window.signals and old_window != self._window:
            window.signals["configure_event"].connect_weak(self._window_configure_event)
            window.signals["map_event"].connect_weak(self._window_visibility_event)
            window.signals["unmap_event"].connect_weak(self._window_visibility_event)
            window.signals["expose_event"].connect_weak(self._window_expose_event)
            if self._xine:
                if old_window and window.get_display() == old_window.get_display():
                    # New window on same display, no need to reconfigure the vo,
                    # we can just point at the new window.
                    self._xine.window_changed(window.get_id(), window.get_size(),
                                              self._window.get_visible(), [])
                elif self._xine_configured:
                    # No previous window, must reconfigure vo.
                    self._xine.configure_video(window.get_id(), window.get_size(),
                                               self.pixel_aspect, config.video.colorkey)

        # Sends a window_changed command to slave.
        if window and self._xine:
            self._window_visibility_event()


    def configure(self):
        if self._xine_configured:
            return

        self._xine_configured = True
        self._xine.set_config(config)
        if self._window:
            self._xine.configure_video(self._window.get_id(), self._window.get_size(),
                                       self.pixel_aspect, config.video.colorkey)
        else:
            self._xine.configure_video(None, None, None, None)
        self._xine.configure_audio(config.audio.driver)
        self._xine.configure_stream(self._properties)


    #
    # Methods for MediaPlayer subclasses
    #

    def open(self, media):
        """
        Open media.
        """
        self._is_in_menu = False
        self._mrl = media.url
        if not self._xine:
            self._child_spawn()

        self.configure()
        self.position = 0.0
        log.debug('xine open %s' % self._mrl)
        self._xine.open(self._mrl)
        self.state = STATE_OPENING


    def play(self):
        """
        Start playback.
        """
        log.debug('play')
        self._xine.play()
        self.set_frame_output_mode()


    def stop(self):
        """
        Stop playback.
        """
        log.debug('xine stop')
        self.state = STATE_STOPPING
        self._xine.stop()


    def pause(self):
        """
        Pause playback.
        """
        self._xine.pause()


    def resume(self):
        """
        Resume playback.
        """
        self._xine.resume()


    def release(self):
        """
        Release audio and video devices.
        """
        if self._xine:
            self.state = STATE_SHUTDOWN
            self._xine.die()


    def seek(self, value, type):
        """
        Seek. Possible types are SEEK_RELATIVE, SEEK_ABSOLUTE and SEEK_PERCENTAGE.
        """
        self._xine.seek(value, type)


    @runtime_policy(DEFER_UNTIL_PLAYING)
    def _set_prop_audio_delay(self, delay):
        """
        Sets audio delay. Positive value defers audio by delay.
        """
        self._xine.set_audio_delay(delay)


    def nav_command(self, input):
        """
        Issue the navigation command to the player.
        """
        map = {
            "up": XINE_EVENT_INPUT_UP,
            "down": XINE_EVENT_INPUT_DOWN,
            "left": XINE_EVENT_INPUT_LEFT,
            "right": XINE_EVENT_INPUT_RIGHT,
            "select": XINE_EVENT_INPUT_SELECT,
            "prev": XINE_EVENT_INPUT_PREVIOUS,
            "next": XINE_EVENT_INPUT_NEXT,
            "angle_prev": XINE_EVENT_INPUT_ANGLE_PREVIOUS,
            "angle_next": XINE_EVENT_INPUT_ANGLE_NEXT,
            "menu1": XINE_EVENT_INPUT_MENU1,
            "menu2": XINE_EVENT_INPUT_MENU2,
            "menu3": XINE_EVENT_INPUT_MENU3,
            "menu4": XINE_EVENT_INPUT_MENU4,
            "0": XINE_EVENT_INPUT_NUMBER_0,
            "1": XINE_EVENT_INPUT_NUMBER_1,
            "2": XINE_EVENT_INPUT_NUMBER_2,
            "3": XINE_EVENT_INPUT_NUMBER_3,
            "4": XINE_EVENT_INPUT_NUMBER_4,
            "5": XINE_EVENT_INPUT_NUMBER_5,
            "6": XINE_EVENT_INPUT_NUMBER_6,
            "7": XINE_EVENT_INPUT_NUMBER_7,
            "8": XINE_EVENT_INPUT_NUMBER_8,
            "9": XINE_EVENT_INPUT_NUMBER_9
        }
        if input in map:
            self._xine.input(map[input])
            return True
        return False


    def is_in_menu(self):
        """
        Return True if the player is in a navigation menu.
        """
        return self._is_in_menu


    def set_property(self, prop, value):
        """
        Set a property to a new value.
        """
        super(Xine, self).set_property(prop, value)
        if self._xine:
            self._xine.set_property(prop, value)

    #
    # Methods and helper for MediaPlayer subclasses for CAP_OSD
    #

    def osd_can_update(self):
        """
        Returns True if it is safe to write to the player's shared memory
        buffer used for OSD, and False otherwise.  If this buffer is written
        to even though this function returns False, the OSD may exhibit
        corrupt output or tearing during animations.
        See generic.osd_can_update for details.
        """
        if not self._osd_shmem:
            return False

        try:
            if ord(self._osd_shmem.read(1)) == BUFFER_UNLOCKED:
                return True
        except kaa.shm.error:
            self._osd_shmem.detach()
            self._osd_shmem = None

        return False


    def osd_update(self, alpha = None, visible = None, invalid_regions = None):
        """
        Updates the OSD of the player based on the given argments.
        See generic.osd_update for details.
        """
        self._xine.osd_update(alpha, visible, invalid_regions)



    #
    # Methods and helper for MediaPlayer subclasses for CAP_CANVAS
    #

    def set_frame_output_mode(self, vo = None, notify = None, size = None):
        """
        Controls if and how frames are delivered via the 'frame' signal, and
        whether or not frames are drawn to the vo driver's video window.
        See generic.set_frame_output_mode for details.
        """
        if vo != None:
            self._cur_frame_output_mode[0] = vo
        if notify != None:
            self._cur_frame_output_mode[1] = notify
        if size != None:
            self._cur_frame_output_mode[2] = size

        if self.state == STATE_OPENING:
            return

        vo, notify, size = self._cur_frame_output_mode
        log.debug('Setting frame output: vo=%s notify=%s size=%s' % (vo, notify, size))
        self._xine.set_frame_output_mode(vo, notify, size)


    def unlock_frame_buffer(self):
        """
        Unlocks the frame buffer provided by the last 'frame' signal
        See generic.unlock_frame_buffer for details.
        """
        offset = self._locked_buffer_offsets.pop(0)
        try:
            self._frame_shmem.write(chr(BUFFER_UNLOCKED), offset)
        except kaa.shm.error:
            self._frame_shmem.detach()
            self._frame_shmem = None