/usr/share/pyshared/perroquetlib/video_player.py is in perroquet 1.1.1-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | # -*- coding: utf-8 -*-
# Copyright (C) 2009-2010 Frédéric Bertolus.
#
# This file is part of Perroquet.
#
# Perroquet is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Perroquet is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Perroquet. If not, see <http://www.gnu.org/licenses/>.
import logging
import sys
import thread
import time
import gst
import gtk
# Build some logger related objects
defaultLoggingHandler = logging.StreamHandler(sys.stdout)
defaultLoggingHandler.setFormatter(logging.Formatter("%(asctime)s.%(msecs)d-[%(name)s::%(levelname)s] %(message)s", "%a %H:%M:%S"))
defaultLoggingLevel = logging.DEBUG
from gettext import gettext as _
from perroquetlib.config import config
class VideoPlayer:
    def __init__(self):
        self.player = gst.Pipeline()
        self.playbin = gst.element_factory_make("playbin2", "player")
        
        # Disable the subtitle display if there is embeded subtitles 
        # (for example, in mkv files)
        #
        # Flags activates some things 
        # (1 << 0) : video
        # (1 << 1) : audio
        # (1 << 4) : software volume
        #
        # The default value is 0, 1, 2, 4. (1 << 2) display the subtitles
        #
        # For more details, see the doc
        # http://www.gstreamer.net/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-playbin2.html#GstPlayFlags
        # http://www.gstreamer.net/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-playbin2.html#GstPlayBin2--flags
        self.playbin.set_property("flags", (1 << 0)|(1 << 1)|(1 << 4))
        
        self.player.add(self.playbin)
        self.logger = logging.Logger("VideoPlayer")
        self.logger.setLevel(defaultLoggingLevel)
        self.logger.addHandler(defaultLoggingHandler)
        #Audio
        audiobin = gst.Bin("audio-speed-bin")
        try:
            self.audiospeedchanger = gst.element_factory_make("pitch")
            self.canChangeSpeed = True
        except gst.ElementNotFoundError:
            self.logger.warn(_(u"You need to install the gstreamer soundtouch elements to "
                             "use slowly play feature."))
            self.canChangeSpeed = False
        #Try to use the pitch element only if it is available
        if self.canChangeSpeed and config.get("interface_use_speed_change"):
            audiobin.add(self.audiospeedchanger)
            self.audiosink = gst.element_factory_make("autoaudiosink")
            audiobin.add(self.audiosink)
            convert = gst.element_factory_make("audioconvert")
            audiobin.add(convert)
            gst.element_link_many(self.audiospeedchanger, convert, self.audiosink)
            sink_pad = gst.GhostPad("sink", self.audiospeedchanger.get_pad("sink"))
            audiobin.add_pad(sink_pad)
            self.playbin.set_property("audio-sink", audiobin)
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.enable_sync_message_emission()
        bus.connect("message", self.on_message)
        bus.connect("sync-message::element", self.on_sync_message)
        self.time_format = gst.Format(gst.FORMAT_TIME)
        self.timeToSeek = -1
        self.speed = 1.0
        self.nextCallbackTime = -1
    def on_message(self, bus, message):
        t = message.type
        if t == gst.MESSAGE_EOS:
            self.player.set_state(gst.STATE_NULL)
        elif t == gst.MESSAGE_ERROR:
            self.player.set_state(gst.STATE_NULL)
            err, debug = message.parse_error()
            self.logger.error("Error: %s" % (err, debug))
    def on_sync_message(self, bus, message):
        if message.structure is None:
            return
        message_name = message.structure.get_name()
        if message_name == "prepare-xwindow-id":
            gtk.gdk.threads_enter()
            gtk.gdk.display_get_default().sync()
            imagesink = message.src
            imagesink.set_property("force-aspect-ratio", True)
            imagesink.set_xwindow_id(self.windowId)
            self.activate_video_area(True)
            gtk.gdk.threads_leave()
    def open(self, path):
        self.playbin.set_property("uri", "file://" + path)
        self.play_thread_id = thread.start_new_thread(self.play_thread, ())
        self.player.set_state(gst.STATE_PAUSED)
        self.playing = False
    def play(self):
        self.player.set_state(gst.STATE_PLAYING)
        self.playing = True
    def set_speed(self, speed):
        if self.canChangeSpeed:
            self.audiospeedchanger.set_property("tempo", speed)
            if self.nextCallbackTime != -1:
                self.nextCallbackTime = self.nextCallbackTime * speed / self.speed
            self.speed = speed
    def pause(self):
        self.player.set_state(gst.STATE_PAUSED)
        self.playing = False
    def is_paused(self):
        return not self.playing
    def is_speed_changeable(self):
        return self.canChangeSpeed
    def seek(self, time):
        value = int(time * 1000000)
        self.playbin.seek_simple(gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, value)
    def seek_as_soon_as_ready(self, time):
        self.timeToSeek = time
    def set_callback(self, callback):
        self.callback = callback
    def set_next_callback_time(self, nextCallbackTime):
        self.nextCallbackTime = nextCallbackTime
    def set_window_id(self, windowId):
        self.windowId = windowId
    def activate_video_callback(self, activate_video):
        self.activate_video_area = activate_video
    def get_current_time(self):
        pos_int = -1
        try:
            pos_int = self.playbin.query_position(self.time_format, None)[0]
        except:
            pass
        if pos_int != -1:
            return int(self.speed * pos_int / 1000000)
        else:
            return None
    def play_thread(self):
        play_thread_id = self.play_thread_id
        while play_thread_id == self.play_thread_id:
            time.sleep(0.1)
            pos_int = -1
            try:
                pos_int = self.player.query_position(self.time_format, None)[0]
            except:
                pass
            if pos_int != -1 and self.nextCallbackTime != -1 and self.speed * pos_int > self.nextCallbackTime * 1000000:
                self.nextCallbackTime = -1
                self.callback()
            if pos_int != -1 and self.timeToSeek != -1:
                self.seek(self.timeToSeek)
                self.timeToSeek = -1
    def close(self):
        self.player.set_state(gst.STATE_NULL)
 |