Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/jukeboxactivity.py
diff options
context:
space:
mode:
authorManuel Kaufmann <humitos@gmail.com>2013-01-14 15:42:35 (GMT)
committer Gonzalo Odiard <godiard@gmail.com>2013-01-25 12:38:40 (GMT)
commit0bf46d8bf132609bab93a93360e78e09f01d7b88 (patch)
tree45cf4f0892622a61b3a06caf8365920dadc7f0b1 /jukeboxactivity.py
parentf4ac3ea1126a571bd0b8e60bcced451066853b9c (diff)
Modularization of classes
- Put each class in a different .py file - Rename jukeboxactivity.py to activity.py to make this more standard Signed-off-by: Manuel Kaufmann <humitos@gmail.com> Reviewed-by: Gonzalo Odiard <gonzalo@laptop.org>
Diffstat (limited to 'jukeboxactivity.py')
-rw-r--r--jukeboxactivity.py841
1 files changed, 0 insertions, 841 deletions
diff --git a/jukeboxactivity.py b/jukeboxactivity.py
deleted file mode 100644
index 1bc4d4a..0000000
--- a/jukeboxactivity.py
+++ /dev/null
@@ -1,841 +0,0 @@
-"""
- jukeboxactivity.py
- Activity that plays media.
- Copyright (C) 2007 Andy Wingo <wingo@pobox.com>
- Copyright (C) 2007 Red Hat, Inc.
- Copyright (C) 2008-2010 Kushal Das <kushal@fedoraproject.org>
-"""
-
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-# USA
-
-import sys
-import logging
-import tempfile
-from gettext import gettext as _
-import os
-
-from sugar3.activity import activity
-from sugar3.graphics.objectchooser import ObjectChooser
-from sugar3 import mime
-from sugar3.datastore import datastore
-
-from sugar3.graphics.toolbarbox import ToolbarBox
-from sugar3.graphics.toolbarbox import ToolbarButton
-from sugar3.activity.widgets import StopButton
-from sugar3.activity.widgets import ActivityToolbarButton
-from sugar3.graphics.alert import ErrorAlert
-from sugar3.graphics.alert import Alert
-
-import gi
-gi.require_version('Gtk', '3.0')
-gi.require_version('Gst', '1.0')
-
-from gi.repository import GObject
-from gi.repository import Gdk
-from gi.repository import Gtk
-from gi.repository import Gst
-from gi.repository import Gio
-
-# Needed for window.get_xid(), xvimagesink.set_window_handle(),
-# respectively:
-from gi.repository import GdkX11, GstVideo
-
-# Avoid "Fatal Python error: GC object already tracked"
-# http://stackoverflow.com/questions/7496629/gstreamer-appsrc-causes-random-crashes
-GObject.threads_init()
-
-# Initialize GStreamer
-Gst.init(None)
-
-import urllib
-from ControlToolbar import Control, ViewToolbar
-from ConfigParser import ConfigParser
-cf = ConfigParser()
-
-from widgets import PlayListWidget
-
-PLAYLIST_WIDTH_PROP = 1.0 / 3
-
-
-class JukeboxActivity(activity.Activity):
- UPDATE_INTERVAL = 500
-
- def __init__(self, handle):
- activity.Activity.__init__(self, handle)
- self._object_id = handle.object_id
- self.set_title(_('Jukebox Activity'))
- self.player = None
- self.max_participants = 1
- self._playlist_jobject = None
-
- toolbar_box = ToolbarBox()
- activity_button = ActivityToolbarButton(self)
- activity_toolbar = activity_button.page
- toolbar_box.toolbar.insert(activity_button, 0)
- self.title_entry = activity_toolbar.title
-
- # FIXME: I don't know what is the mission of this line
- # activity_toolbar.stop.hide()
-
- self.volume_monitor = Gio.VolumeMonitor.get()
- self.volume_monitor.connect('mount-added', self._mount_added_cb)
- self.volume_monitor.connect('mount-removed', self._mount_removed_cb)
-
- _view_toolbar = ViewToolbar()
- _view_toolbar.connect('go-fullscreen',
- self.__go_fullscreen_cb)
- _view_toolbar.connect('toggle-playlist',
- self.__toggle_playlist_cb)
- view_toolbar_button = ToolbarButton(
- page=_view_toolbar,
- icon_name='toolbar-view')
- _view_toolbar.show()
- toolbar_box.toolbar.insert(view_toolbar_button, -1)
- view_toolbar_button.show()
-
- self.control = Control(toolbar_box.toolbar, self)
-
- toolbar_box.toolbar.insert(StopButton(self), -1)
-
- self.set_toolbar_box(toolbar_box)
- toolbar_box.show_all()
-
- self.connect("key_press_event", self._key_press_event_cb)
-
- # We want to be notified when the activity gets the focus or
- # loses it. When it is not active, we don't need to keep
- # reproducing the video
- self.connect("notify::active", self._notify_active_cb)
-
- # FIXME: this is related with shared activity and it doesn't work
- # if handle.uri:
- # pass
- # elif self._shared_activity:
- # if self.get_shared():
- # pass
- # else:
- # # Wait for a successful join before trying to get the document
- # self.connect("joined", self._joined_cb)
-
- self.update_id = -1
- self.changed_id = -1
- self.seek_timeout_id = -1
- self.player = None
- self.uri = None
-
- # {'url': 'file://.../media.ogg', 'title': 'My song', object_id: '..'}
- self.playlist = []
-
- self.jobjectlist = []
- self.playpath = None
- self.currentplaying = None
- self.playflag = False
- self._not_found_files = 0
-
- # README: I changed this because I was getting an error when I
- # tried to modify self.bin with something different than
- # Gtk.Bin
-
- # self.bin = Gtk.HBox()
- # self.bin.show()
-
- self.canvas = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
- self._alert = None
-
- self.playlist_widget = PlayListWidget(self.play)
- self.playlist_widget.update(self.playlist)
- self.playlist_widget.show()
- self.canvas.pack_start(self.playlist_widget, False, True, 0)
- self._empty_widget = Gtk.Label(label="")
- self._empty_widget.show()
- self.videowidget = VideoWidget()
- self.set_canvas(self.canvas)
- self._init_view_area()
- self.show_all()
- self.canvas.connect('size-allocate', self.__size_allocate_cb)
-
- #From ImageViewer Activity
- self._want_document = True
- if self._object_id is None:
- self._show_object_picker = GObject.timeout_add(1000, \
- self._show_picker_cb)
-
- if handle.uri:
- self.uri = handle.uri
- GObject.idle_add(self._start, self.uri, handle.title)
-
- # Create the player just once
- logging.debug('Instantiating GstPlayer')
- self.player = GstPlayer(self.videowidget)
- self.player.connect("eos", self._player_eos_cb)
- self.player.connect("error", self._player_error_cb)
- self.p_position = Gst.CLOCK_TIME_NONE
- self.p_duration = Gst.CLOCK_TIME_NONE
-
- def _notify_active_cb(self, widget, event):
- """Sugar notify us that the activity is becoming active or inactive.
- When we are inactive, we stop the player if it is reproducing
- a video.
- """
- if self.player.player.props.uri is not None:
- if not self.player.is_playing() and self.props.active:
- self.player.play()
- if self.player.is_playing() and not self.props.active:
- self.player.pause()
-
- def _init_view_area(self):
- """
- Use a notebook with two pages, one empty an another
- with the videowidget
- """
- self.view_area = Gtk.Notebook()
- self.view_area.set_show_tabs(False)
- self.view_area.append_page(self._empty_widget, None)
- self.view_area.append_page(self.videowidget, None)
- self.canvas.pack_end(self.view_area, expand=True,
- fill=True, padding=0)
-
- def _switch_canvas(self, show_video):
- """Show or hide the video visualization in the canvas.
-
- When hidden, the canvas is filled with an empty widget to
- ensure redrawing.
-
- """
- if show_video:
- self.view_area.set_current_page(1)
- else:
- self.view_area.set_current_page(0)
- self.canvas.queue_draw()
-
- def __size_allocate_cb(self, widget, allocation):
- canvas_size = self.canvas.get_allocation()
- playlist_width = int(canvas_size.width * PLAYLIST_WIDTH_PROP)
- self.playlist_widget.set_size_request(playlist_width, 0)
-
- def open_button_clicked_cb(self, widget):
- """ To open the dialog to select a new file"""
- #self.player.seek(0L)
- #self.player.stop()
- #self.playlist = []
- #self.playpath = None
- #self.currentplaying = None
- #self.playflag = False
- self._want_document = True
- self._show_object_picker = GObject.timeout_add(1, self._show_picker_cb)
-
- def _key_press_event_cb(self, widget, event):
- keyname = Gdk.keyval_name(event.keyval)
- logging.info("Keyname Press: %s, time: %s", keyname, event.time)
- if self.title_entry.has_focus():
- return False
-
- if keyname == "space":
- self.play_toggled()
- return True
-
- def check_if_next_prev(self):
- if self.currentplaying == 0:
- self.control.prev_button.set_sensitive(False)
- else:
- self.control.prev_button.set_sensitive(True)
- if self.currentplaying == len(self.playlist) - 1:
- self.control.next_button.set_sensitive(False)
- else:
- self.control.next_button.set_sensitive(True)
-
- def songchange(self, direction):
- #if self.playflag:
- # self.playflag = False
- # return
- self.player.seek(0L)
- if direction == "prev" and self.currentplaying > 0:
- self.play(self.currentplaying - 1)
- logging.info("prev: " + self.playlist[self.currentplaying]['url'])
- #self.playflag = True
- elif direction == "next" and \
- self.currentplaying < len(self.playlist) - 1:
- self.play(self.currentplaying + 1)
- logging.info("next: " + self.playlist[self.currentplaying]['url'])
- #self.playflag = True
- else:
- self.play_toggled()
- self.player.stop()
- self._switch_canvas(show_video=False)
- self.player.set_uri(None)
- self.check_if_next_prev()
-
- def play(self, media_index):
- self._switch_canvas(show_video=True)
- self.currentplaying = media_index
- url = self.playlist[self.currentplaying]['url']
- error = None
- if url.startswith('journal://'):
- try:
- jobject = datastore.get(url[len("journal://"):])
- url = 'file://' + jobject.file_path
- except:
- path = url[len("journal://"):]
- error = _('The file %s was not found') % path
-
- self.check_if_next_prev()
-
- if error is None:
- self.player.set_uri(url)
- self.player.play()
- else:
- self.control.set_disabled()
- self._show_error_alert(error)
-
- self.playlist_widget.set_cursor(self.currentplaying)
-
- def _player_eos_cb(self, widget):
- self.songchange('next')
-
- def _show_error_alert(self, title, msg=None):
- self._alert = ErrorAlert()
- self._alert.props.title = title
- if msg is not None:
- self._alert.props.msg = msg
- self.add_alert(self._alert)
- self._alert.connect('response', self._alert_cancel_cb)
- self._alert.show()
-
- def _mount_added_cb(self, volume_monitor, device):
- self.view_area.set_current_page(0)
- self.remove_alert(self._alert)
- self.playlist_widget.update(self.playlist)
-
- def _mount_removed_cb(self, volume_monitor, device):
- self.view_area.set_current_page(0)
- self.remove_alert(self._alert)
- self.playlist_widget.update(self.playlist)
-
- def _show_missing_tracks_alert(self, nro):
- self._alert = Alert()
- title = _('%s tracks not found.') % nro
- self._alert.props.title = title
- self._alert.add_button(Gtk.ResponseType.APPLY, _('Details'))
- self.add_alert(self._alert)
- self._alert.connect('response',
- self.__missing_tracks_alert_response_cb)
-
- def __missing_tracks_alert_response_cb(self, alert, response_id):
- vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
- vbox.props.valign = Gtk.Align.CENTER
- label = Gtk.Label(label='')
- label.set_markup(_('<b>Missing tracks</b>'))
- vbox.pack_start(label, False, False, 15)
-
- for track in self.playlist_widget.get_missing_tracks():
- path = track['url'].replace('journal://', '')\
- .replace('file://', '')
- label = Gtk.Label(label=path)
- vbox.add(label)
-
- _missing_tracks = Gtk.ScrolledWindow()
- _missing_tracks.add_with_viewport(vbox)
- _missing_tracks.show_all()
-
- self.view_area.append_page(_missing_tracks, None)
-
- self.view_area.set_current_page(2)
- self.remove_alert(alert)
-
- def _alert_cancel_cb(self, alert, response_id):
- self.remove_alert(alert)
-
- def _player_error_cb(self, widget, message, detail):
- self.player.stop()
- self.player.set_uri(None)
- self.control.set_disabled()
-
- file_path = self.playlist[self.currentplaying]['url']\
- .replace('journal://', 'file://')
- mimetype = mime.get_for_file(file_path)
-
- title = _('Error')
- msg = _('This "%s" file can\'t be played') % mimetype
- self._switch_canvas(False)
- self._show_error_alert(title, msg)
-
- def _joined_cb(self, activity):
- logging.debug("someone joined")
- pass
-
- def _shared_cb(self, activity):
- logging.debug("shared start")
- pass
-
- def _show_picker_cb(self):
- #From ImageViewer Activity
- if not self._want_document:
- return
-
- # README: some arguments are deprecated so I avoid them
-
- # chooser = ObjectChooser(_('Choose document'), self,
- # Gtk.DialogFlags.MODAL |
- # Gtk.DialogFlags.DESTROY_WITH_PARENT,
- # what_filter=mime.GENERIC_TYPE_AUDIO)
-
- chooser = ObjectChooser(self, what_filter=mime.GENERIC_TYPE_AUDIO)
-
- try:
- result = chooser.run()
- if result == Gtk.ResponseType.ACCEPT:
- jobject = chooser.get_selected_object()
- if jobject and jobject.file_path:
- logging.error('Adding %s', jobject.file_path)
- title = jobject.metadata.get('title', None)
- self._load_file(jobject.file_path, title,
- jobject.object_id)
- finally:
- #chooser.destroy()
- #del chooser
- pass
-
- def read_file(self, file_path):
- """Load a file from the datastore on activity start."""
- logging.debug('JukeBoxAtivity.read_file: %s', file_path)
- title = self.metadata.get('title', None)
- self._load_file(file_path, title, self._object_id)
-
- def _load_file(self, file_path, title, object_id):
- self.uri = os.path.abspath(file_path)
- if os.path.islink(self.uri):
- self.uri = os.path.realpath(self.uri)
- mimetype = mime.get_for_file('file://' + file_path)
- logging.error('read_file mime %s', mimetype)
- if mimetype == 'audio/x-mpegurl':
- # is a M3U playlist:
- for uri in self._read_m3u_playlist(file_path):
- if not self.playlist_widget.check_available_media(uri['url']):
- self._not_found_files += 1
-
- GObject.idle_add(self._start, uri['url'], uri['title'],
- uri['object_id'])
- else:
- # is another media file:
- GObject.idle_add(self._start, self.uri, title, object_id)
-
- if self._not_found_files > 0:
- self._show_missing_tracks_alert(self._not_found_files)
-
- def _create_playlist_jobject(self):
- """Create an object in the Journal to store the playlist.
-
- This is needed if the activity was not started from a playlist
- or from scratch.
-
- """
- jobject = datastore.create()
- jobject.metadata['mime_type'] = "audio/x-mpegurl"
- jobject.metadata['title'] = _('Jukebox playlist')
-
- temp_path = os.path.join(activity.get_activity_root(),
- 'instance')
- if not os.path.exists(temp_path):
- os.makedirs(temp_path)
-
- jobject.file_path = tempfile.mkstemp(dir=temp_path)[1]
- self._playlist_jobject = jobject
-
- def write_file(self, file_path):
-
- def write_playlist_to_file(file_path):
- """Open the file at file_path and write the playlist.
-
- It is saved in audio/x-mpegurl format.
-
- """
- list_file = open(file_path, 'w')
- for uri in self.playlist:
- list_file.write('#EXTINF: %s\n' % uri['title'])
- list_file.write('%s\n' % uri['url'])
- list_file.close()
-
- if not self.metadata['mime_type']:
- self.metadata['mime_type'] = 'audio/x-mpegurl'
-
- if self.metadata['mime_type'] == 'audio/x-mpegurl':
- write_playlist_to_file(file_path)
-
- else:
- if self._playlist_jobject is None:
- self._create_playlist_jobject()
-
- # Add the playlist to the playlist jobject description.
- # This is only done if the activity was not started from a
- # playlist or from scratch:
- description = ''
- for uri in self.playlist:
- description += '%s\n' % uri['title']
- self._playlist_jobject.metadata['description'] = description
-
- write_playlist_to_file(self._playlist_jobject.file_path)
- datastore.write(self._playlist_jobject)
-
- def _read_m3u_playlist(self, file_path):
- urls = []
- title = ''
- for line in open(file_path).readlines():
- line = line.strip()
- if line != '':
- if line.startswith('#EXTINF:'):
- # line with data
- #EXTINF: title
- title = line[len('#EXTINF:'):]
- else:
- uri = {}
- uri['url'] = line.strip()
- uri['title'] = title
- if uri['url'].startswith('journal://'):
- uri['object_id'] = uri['url'][len('journal://'):]
- else:
- uri['object_id'] = None
- urls.append(uri)
- title = ''
- return urls
-
- def _start(self, uri=None, title=None, object_id=None):
- self._want_document = False
- self.playpath = os.path.dirname(uri)
- if not uri:
- return False
-
- if title is not None:
- title = title.strip()
- if object_id is not None:
- self.playlist.append({'url': 'journal://' + object_id,
- 'title': title})
- else:
- if uri.startswith("file://"):
- self.playlist.append({'url': uri, 'title': title})
- else:
- uri = "file://" + urllib.quote(os.path.abspath(uri))
- self.playlist.append({'url': uri, 'title': title})
-
- self.playlist_widget.update(self.playlist)
-
- try:
- if self.currentplaying is None:
- logging.info("Playing: " + self.playlist[0]['url'])
- url = self.playlist[0]['url']
- if url.startswith('journal://'):
- jobject = datastore.get(url[len("journal://"):])
- url = 'file://' + jobject.file_path
-
- self.player.set_uri(url)
- self.player.play()
- self.currentplaying = 0
- self.play_toggled()
- self.show_all()
- else:
- pass
- #self.player.seek(0L)
- #self.player.stop()
- #self.currentplaying += 1
- #self.player.set_uri(self.playlist[self.currentplaying])
- #self.play_toggled()
- except:
- pass
- self.check_if_next_prev()
- return False
-
- def play_toggled(self):
- self.control.set_enabled()
-
- if self.player.is_playing():
- self.player.pause()
- self.control.set_button_play()
- else:
- if self.player.error:
- self.control.set_disabled()
- else:
- self.player.play()
- if self.update_id == -1:
- self.update_id = GObject.timeout_add(self.UPDATE_INTERVAL,
- self.update_scale_cb)
- self.control.set_button_pause()
-
- def volume_changed_cb(self, widget, value):
- if self.player:
- self.player.player.set_property('volume', value)
-
- def scale_button_press_cb(self, widget, event):
- self.control.button.set_sensitive(False)
- self.was_playing = self.player.is_playing()
- if self.was_playing:
- self.player.pause()
-
- # don't timeout-update position during seek
- if self.update_id != -1:
- GObject.source_remove(self.update_id)
- self.update_id = -1
-
- # make sure we get changed notifies
- if self.changed_id == -1:
- self.changed_id = self.control.hscale.connect('value-changed',
- self.scale_value_changed_cb)
-
- def scale_value_changed_cb(self, scale):
- # see seek.c:seek_cb
- real = long(scale.get_value() * self.p_duration / 100) # in ns
- self.player.seek(real)
- # allow for a preroll
- self.player.get_state(timeout=50 * Gst.MSECOND) # 50 ms
-
- def scale_button_release_cb(self, widget, event):
- # see seek.cstop_seek
- widget.disconnect(self.changed_id)
- self.changed_id = -1
-
- self.control.button.set_sensitive(True)
- if self.seek_timeout_id != -1:
- GObject.source_remove(self.seek_timeout_id)
- self.seek_timeout_id = -1
- else:
- if self.was_playing:
- self.player.play()
-
- if self.update_id != -1:
- self.error('Had a previous update timeout id')
- else:
- self.update_id = GObject.timeout_add(self.UPDATE_INTERVAL,
- self.update_scale_cb)
-
- def update_scale_cb(self):
- success, self.p_position, self.p_duration = \
- self.player.query_position()
-
- if not success:
- return True
-
- if self.p_position != Gst.CLOCK_TIME_NONE:
- value = self.p_position * 100.0 / self.p_duration
- self.control.adjustment.set_value(value)
-
- # Update the current time
- seconds = self.p_position * 10 ** -9
- time = '%2d:%02d' % (int(seconds / 60), int(seconds % 60))
- self.control.current_time_label.set_text(time)
-
- # FIXME: this should be updated just once when the file starts
- # the first time
- if self.p_duration != Gst.CLOCK_TIME_NONE:
- seconds = self.p_duration * 10 ** -9
- time = '%2d:%02d' % (int(seconds / 60), int(seconds % 60))
- self.control.total_time_label.set_text(time)
-
- return True
-
- def _erase_playlist_entry_clicked_cb(self, widget):
- self.playlist_widget.delete_selected_items()
-
- def __go_fullscreen_cb(self, toolbar):
- self.fullscreen()
-
- def __toggle_playlist_cb(self, toolbar):
- if self.playlist_widget.get_visible():
- self.playlist_widget.hide()
- else:
- self.playlist_widget.show_all()
- self.canvas.queue_draw()
-
-
-class GstPlayer(GObject.GObject):
-
- __gsignals__ = {
- 'error': (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
- 'eos': (GObject.SignalFlags.RUN_FIRST, None, []),
- }
-
- def __init__(self, videowidget):
- GObject.GObject.__init__(self)
-
- self.playing = False
- self.error = False
-
- # Create GStreamer pipeline
- self.pipeline = Gst.Pipeline()
- # Create bus to get events from GStreamer pipeline
- self.bus = self.pipeline.get_bus()
- self.bus.add_signal_watch()
-
- self.bus.connect('message::eos', self.__on_eos_message)
- self.bus.connect('message::error', self.__on_error_message)
-
- # This is needed to make the video output in our DrawingArea
- self.bus.enable_sync_message_emission()
- self.bus.connect('sync-message::element', self.__on_sync_message)
-
- # Create GStreamer elements
- self.player = Gst.ElementFactory.make('playbin', None)
- self.pipeline.add(self.player)
-
- # Set the proper flags to render the vis-plugin
- GST_PLAY_FLAG_VIS = 1 << 3
- GST_PLAY_FLAG_TEXT = 1 << 2
- self.player.props.flags |= GST_PLAY_FLAG_VIS
- self.player.props.flags |= GST_PLAY_FLAG_TEXT
-
- r = Gst.Registry.get()
- l = [x for x in r.get_feature_list(Gst.ElementFactory)
- if (x.get_metadata('klass') == "Visualization")]
- if len(l):
- e = l.pop() # take latest plugin in the list
- vis_plug = Gst.ElementFactory.make(e.get_name(), e.get_name())
- self.player.set_property('vis-plugin', vis_plug)
-
- self.overlay = None
- videowidget.realize()
- self.videowidget = videowidget
- self.videowidget_xid = videowidget.get_window().get_xid()
- self._init_video_sink()
-
- def __on_error_message(self, bus, msg):
- self.stop()
- self.playing = False
- self.error = True
- err, debug = msg.parse_error()
- self.emit('error', err, debug)
-
- def __on_eos_message(self, bus, msg):
- logging.debug('SIGNAL: eos')
- self.playing = False
- self.emit('eos')
-
- def __on_sync_message(self, bus, msg):
- if msg.get_structure().get_name() == 'prepare-window-handle':
- msg.src.set_window_handle(self.videowidget_xid)
-
- def set_uri(self, uri):
- self.pipeline.set_state(Gst.State.READY)
- logging.debug('### Setting URI: %s', uri)
- self.player.set_property('uri', uri)
-
- def _init_video_sink(self):
- self.bin = Gst.Bin()
- videoscale = Gst.ElementFactory.make('videoscale', 'videoscale')
- self.bin.add(videoscale)
- pad = videoscale.get_static_pad("sink")
- ghostpad = Gst.GhostPad.new("sink", pad)
- self.bin.add_pad(ghostpad)
- videoscale.set_property("method", 0)
-
- textoverlay = Gst.ElementFactory.make('textoverlay', 'textoverlay')
- self.overlay = textoverlay
- self.bin.add(textoverlay)
- conv = Gst.ElementFactory.make("videoconvert", "conv")
- self.bin.add(conv)
- videosink = Gst.ElementFactory.make('autovideosink', 'autovideosink')
- self.bin.add(videosink)
-
- videoscale.link(textoverlay)
- textoverlay.link(conv)
- conv.link(videosink)
-
- self.player.set_property("video-sink", self.bin)
-
- def set_overlay(self, title, artist, album):
- text = "%s\n%s" % (title, artist)
- if album and len(album):
- text += "\n%s" % album
- self.overlay.set_property("text", text)
- self.overlay.set_property("font-desc", "sans bold 14")
- self.overlay.set_property("halignment", "right")
- self.overlay.set_property("valignment", "bottom")
- try:
- # Only in OLPC versions of gstreamer-plugins-base for now
- self.overlay.set_property("line-align", "left")
- except:
- pass
-
- def query_position(self):
- "Returns a (position, duration) tuple"
-
- p_success, position = self.player.query_position(Gst.Format.TIME)
- d_success, duration = self.player.query_duration(Gst.Format.TIME)
-
- return (p_success and d_success, position, duration)
-
- def seek(self, location):
- """
- @param location: time to seek to, in nanoseconds
- """
-
- logging.debug('Seek: %s ns', location)
-
- self.pipeline.seek_simple(Gst.Format.TIME,
- Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
- location)
-
- def pause(self):
- logging.debug("pausing player")
- self.pipeline.set_state(Gst.State.PAUSED)
- self.playing = False
-
- def play(self):
- logging.debug("playing player")
- self.pipeline.set_state(Gst.State.PLAYING)
- self.playing = True
- self.error = False
-
- def stop(self):
- self.playing = False
- self.pipeline.set_state(Gst.State.NULL)
- logging.debug("stopped player")
-
- def get_state(self, timeout=1):
- return self.player.get_state(timeout=timeout)
-
- def is_playing(self):
- return self.playing
-
-
-class VideoWidget(Gtk.DrawingArea):
- def __init__(self):
- GObject.GObject.__init__(self)
- self.set_events(Gdk.EventMask.POINTER_MOTION_MASK |
- Gdk.EventMask.POINTER_MOTION_HINT_MASK |
- Gdk.EventMask.EXPOSURE_MASK |
- Gdk.EventMask.KEY_PRESS_MASK |
- Gdk.EventMask.KEY_RELEASE_MASK)
-
- self.set_app_paintable(True)
- self.set_double_buffered(False)
-
-
-if __name__ == '__main__':
- window = Gtk.Window()
- view = VideoWidget()
-
- #player.connect("eos", self._player_eos_cb)
- #player.connect("error", self._player_error_cb)
- view.show()
- window.add(view)
-
- def map_cb(widget):
- player = GstPlayer(view)
- player.set_uri(sys.argv[1])
- player.play()
-
- window.connect('map', map_cb)
- window.maximize()
- window.show_all()
- window.connect("destroy", Gtk.main_quit)
- Gtk.main()