Added gui msg within MenuMgr
Converted TV player to read directly from the socket file descriptor. I think the GST buffer is too small however as it jerks.
This commit is contained in:
parent
1593e437b5
commit
a3351b2c66
113
MenuMgr.py
113
MenuMgr.py
|
@ -3,6 +3,7 @@ from SkinMgr import SkinMgr
|
|||
from Spinner import Spinner
|
||||
import pygtk
|
||||
import gtk
|
||||
import pango
|
||||
|
||||
class MenuMgr:
|
||||
|
||||
|
@ -11,6 +12,7 @@ class MenuMgr:
|
|||
self.menus = []
|
||||
self.menuHistory = [] #A list that contains menus in the order that they've been viewed
|
||||
self.currentMenu = None
|
||||
self.uiMsg = message(stage)
|
||||
|
||||
self.skinMgr = SkinMgr(self.stage)
|
||||
background = self.skinMgr.get_Background()
|
||||
|
@ -108,21 +110,30 @@ class MenuMgr:
|
|||
self.currentMenu = toMenu
|
||||
|
||||
def on_key_press_event (self, stage, event):
|
||||
#Firstly checking whether we are in the process of running a plugin (And that the key isn't escape)
|
||||
#Firstly check whether any messages are currently displayed
|
||||
if self.uiMsg.active:
|
||||
self.uiMsg.on_key_press_event(stage, event)
|
||||
return
|
||||
|
||||
#Secondly, checking whether we are in the process of running a plugin (And that the key isn't escape)
|
||||
if (not self.currentPlugin == None) and (not event.keyval == clutter.keysyms.Escape):
|
||||
#If it is, simply pass the event details along to the plugin
|
||||
self.currentPlugin.on_key_press_event(stage, event)
|
||||
return None
|
||||
|
||||
#print event.hardware_keycode
|
||||
|
||||
# If none of these things, the menu needs to do something
|
||||
if event.keyval == clutter.keysyms.Up: #Up button pressed
|
||||
self.currentMenu.selectPrevious()
|
||||
if event.keyval == clutter.keysyms.Down: #Down button pressed
|
||||
self.currentMenu.selectNext()
|
||||
if event.keyval == clutter.keysyms.q:
|
||||
clutter.main_quit()
|
||||
if event.hardware_keycode == 36: #return button pressed
|
||||
#self.aList.set_processing(True)
|
||||
if event.keyval == clutter.keysyms.Return: #return button pressed
|
||||
# Need to decide what action to take
|
||||
# Options are:
|
||||
# 1) Switch to a new menu
|
||||
# 2) Launch a module
|
||||
action = self.currentMenu.get_current_item().getAction()
|
||||
if action.__class__.__name__ == "Menu": # Check whether we're a pointing to a menu object
|
||||
self.transition_fade_zoom(self.currentMenu, action)
|
||||
|
@ -131,6 +142,7 @@ class MenuMgr:
|
|||
#We have a plugin and need to start it
|
||||
self.currentPlugin = action
|
||||
action.begin( self )
|
||||
# This is tres bodge
|
||||
if event.keyval == clutter.keysyms.Escape:
|
||||
#If there's a plugin running then end it
|
||||
if not self.currentPlugin == None:
|
||||
|
@ -154,6 +166,9 @@ class MenuMgr:
|
|||
self.transition_fade_zoom(self.menuHistory.pop(), self.menuHistory[-1])
|
||||
self.currentMenu = self.menuHistory[-1]
|
||||
|
||||
def display_msg(self, title, msg):
|
||||
self.uiMsg.display_msg(title, msg)
|
||||
|
||||
class MenuSelector(clutter.Texture):
|
||||
x_offset = -50
|
||||
width = 400
|
||||
|
@ -243,3 +258,93 @@ class MenuSelector(clutter.Texture):
|
|||
def get_width(self):
|
||||
return self.width
|
||||
|
||||
class message():
|
||||
font = "Lucida Grande "
|
||||
message_font_size = 30
|
||||
detail_font_size = 22
|
||||
|
||||
def __init__(self, stage):
|
||||
self.stage = stage
|
||||
self.active = False
|
||||
|
||||
self.backdrop = clutter.Rectangle()
|
||||
self.backdrop.set_color(clutter.color_parse('Black'))
|
||||
#self.backdrop.set_opacity(240)
|
||||
self.backdrop.set_width(self.stage.get_width())
|
||||
self.backdrop.set_height(self.stage.get_height())
|
||||
|
||||
self.main_group = clutter.Group()
|
||||
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file("ui/splash_box.png")
|
||||
self.box = clutter.Texture()
|
||||
self.box.set_pixbuf(pixbuf)
|
||||
self.box.set_opacity(int(255 * 0.75))
|
||||
self.box.set_height(int(self.stage.get_height()* 0.3))
|
||||
self.main_group.add(self.box)
|
||||
|
||||
self.message = clutter.Label()
|
||||
self.message.set_font_name(self.font + str(self.message_font_size))
|
||||
self.message.set_color(clutter.color_parse('White'))
|
||||
pos_x = int(self.box.get_width() * 0.10)
|
||||
pos_y = int(self.box.get_height() * 0.10)
|
||||
self.message.set_position(pos_x, pos_y)
|
||||
width = int(self.box.get_width() * 0.80) #Width is 80% of the box, giving 10% gap each side
|
||||
self.message.set_width(width)
|
||||
self.message.set_ellipsize(pango.ELLIPSIZE_END)
|
||||
self.message.set_text("")
|
||||
self.main_group.add(self.message)
|
||||
|
||||
self.detail = clutter.Label()
|
||||
self.detail.set_font_name(self.font + str(self.detail_font_size))
|
||||
self.detail.set_color(clutter.color_parse('White'))
|
||||
pos_x = self.message.get_x()
|
||||
pos_y = self.message.get_y() + self.message.get_height()
|
||||
self.detail.set_position(pos_x, pos_y)
|
||||
height = self.box.get_height() - pos_y
|
||||
self.detail.set_height(height)
|
||||
#self.detail.set_ellipsize(pango.ELLIPSIZE_END)
|
||||
self.main_group.add(self.detail)
|
||||
self.detail.set_line_wrap(True)
|
||||
|
||||
group_x = (self.stage.get_width()/2) - (self.box.get_width()/2)
|
||||
group_y = (self.stage.get_height()/2) - (self.box.get_height()/2)
|
||||
self.main_group.set_position(group_x, group_y)
|
||||
|
||||
def display_msg(self, title, text):
|
||||
self.active = True
|
||||
|
||||
self.message.set_text(title)
|
||||
self.detail.set_text(text)
|
||||
width = int(self.box.get_width() * 0.80) #Width is 80% of the box, giving 10% gap each side
|
||||
self.detail.set_width(width)
|
||||
self.message.set_width(width)
|
||||
|
||||
|
||||
self.main_group.set_opacity(0)
|
||||
self.backdrop.set_opacity(0)
|
||||
self.stage.add(self.backdrop)
|
||||
self.stage.add(self.main_group)
|
||||
self.main_group.show_all()
|
||||
self.backdrop.show()
|
||||
|
||||
self.timeline = clutter.Timeline(10,30)
|
||||
alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func)
|
||||
self.behaviour_group = clutter.BehaviourOpacity(alpha, 0, 255)
|
||||
self.behaviour_backdrop = clutter.BehaviourOpacity(alpha, 0, 180)
|
||||
self.behaviour_group.apply(self.main_group)
|
||||
self.behaviour_backdrop.apply(self.backdrop)
|
||||
self.timeline.start()
|
||||
|
||||
def hide_msg(self):
|
||||
self.active = False
|
||||
|
||||
self.timeline = clutter.Timeline(10,30)
|
||||
alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func)
|
||||
self.behaviour_group = clutter.BehaviourOpacity(alpha, 255, 0)
|
||||
self.behaviour_backdrop = clutter.BehaviourOpacity(alpha, 180, 0)
|
||||
self.behaviour_group.apply(self.main_group)
|
||||
self.behaviour_backdrop.apply(self.backdrop)
|
||||
self.timeline.start()
|
||||
|
||||
def on_key_press_event (self, stage, event):
|
||||
self.hide_msg()
|
BIN
MenuMgr.pyc
BIN
MenuMgr.pyc
Binary file not shown.
|
@ -1,5 +1,6 @@
|
|||
import sys, clutter, clutter.cluttergst, gst, pygst, gtk, pygtk, gobject
|
||||
import threading
|
||||
import os
|
||||
|
||||
|
||||
class VideoController:
|
||||
|
@ -35,29 +36,38 @@ class VideoController:
|
|||
def play_video(self, uri, player):
|
||||
self.player = player
|
||||
self.stage.add(self.video_texture)
|
||||
#f = open("/home/josh/eclipse/gloss-mc/test.mpg",'r')
|
||||
#fd = os.dup(f.fileno())
|
||||
#uri = "fd://" + str(fd)
|
||||
#print "New URI: " + uri
|
||||
self.video_texture.set_uri(uri)
|
||||
self.video_texture.set_position(0, 0)
|
||||
self.video_texture.show()
|
||||
|
||||
#We need to connect to the message queue on the playbin to watch for any message (ie codec or file not found errors)
|
||||
self.bin = self.video_texture.get_playbin()
|
||||
bus = self.video_texture.get_playbin().get_bus()
|
||||
bus.add_signal_watch()
|
||||
bus.connect('message', self.on_bus_message)
|
||||
|
||||
#Now we can start the video
|
||||
self.video_texture.set_playing(True)
|
||||
self.bin.set_state(gst.STATE_PAUSED)
|
||||
self.isPlaying = True
|
||||
|
||||
return self.video_texture
|
||||
|
||||
#This handles any messages that are sent accross the playbin
|
||||
#Currently the only message being checked for it a "codec not found"
|
||||
#Currently this is checking two types of msgs:
|
||||
# 1) A "codec not found" warning, at which stage playback is stopped
|
||||
# 2) A Buffering msg. This pauses the video until the buffer is at 100%
|
||||
def on_bus_message(self, bus, message):
|
||||
t = message.type
|
||||
|
||||
print "message type: " + str(t)
|
||||
if t == gst.MESSAGE_ELEMENT:
|
||||
#This occurs when an invalid codec is attempted to be played
|
||||
#Need to insert some form of message to the user here
|
||||
#print "Element: " + message.structure.to_string()
|
||||
struc = message.structure
|
||||
if struc is None:
|
||||
return
|
||||
|
@ -66,8 +76,20 @@ class VideoController:
|
|||
self.isPlaying = False
|
||||
self.video_texture.set_playing(False)
|
||||
self.player.stop_video()
|
||||
if t == gst.MESSAGE_BUFFERING:
|
||||
percent = message.parse_buffering()
|
||||
print "Buffer: " + str(percent)
|
||||
if percent < 100:
|
||||
self.bin.set_state(gst.STATE_PAUSED)
|
||||
else:
|
||||
self.bin.set_state(gst.STATE_PLAYING)
|
||||
if t == gst.MESSAGE_STATE_CHANGED:
|
||||
prev, current, next = message.parse_state_changed()
|
||||
print "State Changed. Previous state: " + str(prev)
|
||||
print "State Changed. Current state: " + str(current)
|
||||
elif t == gst.STREAM_ERROR:
|
||||
print "OHH NOES!"
|
||||
#print "OHH NOES!"
|
||||
print "GST Message: " + message.structure.to_string()
|
||||
|
||||
def stop_video(self):
|
||||
if self.video_texture.get_playing():
|
||||
|
@ -92,9 +114,9 @@ class VideoController:
|
|||
self.stage.remove(self.blackdrop)
|
||||
self.blackdrop = None
|
||||
|
||||
def customBin(self):
|
||||
self.src = gst.element_factory_make("filesrc", "src");
|
||||
self.src.set_property("location", "/home/josh/clutter/toys/gloss/test.mpg")
|
||||
def customBin(self, fd):
|
||||
self.src = gst.element_factory_make("fdsrc", "src");
|
||||
self.src.set_property("fd", fd)
|
||||
self.demux = gst.element_factory_make("ffdemux_mpegts", "demux")
|
||||
self.queue1 = gst.element_factory_make("queue", "queue1")
|
||||
self.queue2 = gst.element_factory_make("queue", "queue2")
|
||||
|
|
|
@ -167,24 +167,28 @@ class MythBackendConnection(threading.Thread):
|
|||
|
||||
def buffer_live(self, cmd_sock, data_sock, socket_id):
|
||||
#Create a buffer file
|
||||
buffer_file_name = "test.mpg"
|
||||
self.buffer_file = open(buffer_file_name,"w")
|
||||
#buffer_file_name = "test.mpg"
|
||||
#self.buffer_file = open(buffer_file_name,"w")
|
||||
request_size = 32768
|
||||
max_request_size = 135000
|
||||
#max_request_size = 135000
|
||||
max_request_size = 270000
|
||||
request_size_step = 16384
|
||||
|
||||
#Need to create a bit of a buffer so playback will begin
|
||||
"""
|
||||
x=0
|
||||
while x<80:
|
||||
transfer_cmd = "QUERY_FILETRANSFER "+ str(socket_id) + "[]:[]REQUEST_BLOCK[]:[]"+str(request_size)
|
||||
self.send_cmd(cmd_sock, transfer_cmd)
|
||||
num_bytes = int(self.receive_reply(cmd_sock))
|
||||
data = data_sock.recv(num_bytes)
|
||||
self.buffer_file.write(data)
|
||||
#self.buffer_file.write(data)
|
||||
x=x+1
|
||||
self.buffer_file.flush()
|
||||
self.videoPlayer.begin_playback(buffer_file_name)
|
||||
#self.videoPlayer.begin_playback(self.data_sock.fileno())
|
||||
#self.buffer_file.flush()
|
||||
"""
|
||||
#self.videoPlayer.begin_playback(buffer_file_name)
|
||||
reader_fd = os.dup(data_sock.fileno())
|
||||
self.videoPlayer.begin_playback(reader_fd)
|
||||
|
||||
print "BEGINNING PLAYBACK!"
|
||||
self.Playing = True
|
||||
|
@ -192,8 +196,8 @@ class MythBackendConnection(threading.Thread):
|
|||
transfer_cmd = "QUERY_FILETRANSFER "+ str(socket_id) + "[]:[]REQUEST_BLOCK[]:[]"+str(request_size)
|
||||
self.send_cmd(cmd_sock, transfer_cmd)
|
||||
num_bytes = int(self.receive_reply(cmd_sock))
|
||||
data = data_sock.recv(num_bytes)
|
||||
self.buffer_file.write(data)
|
||||
data_sock.recv(num_bytes)
|
||||
#self.buffer_file.write(data)
|
||||
|
||||
#This tries to optimise the request size
|
||||
#print "Received: " + str(num_bytes)
|
||||
|
@ -201,12 +205,12 @@ class MythBackendConnection(threading.Thread):
|
|||
request_size = request_size + request_size_step
|
||||
if request_size > max_request_size:
|
||||
request_size = max_request_size
|
||||
elif (request_size > request_size_step):
|
||||
elif (request_size > request_size_step) and (num_bytes != request_size):
|
||||
request_size = request_size - request_size_step
|
||||
|
||||
|
||||
print "Ending playback"
|
||||
self.buffer_file.close()
|
||||
#self.buffer_file.close()
|
||||
|
||||
def message_socket_mgr(self, msg_socket):
|
||||
#Do the protocol version check
|
||||
|
|
|
@ -34,35 +34,14 @@ class Module:
|
|||
|
||||
self.isRunning = True
|
||||
|
||||
def begin_playback(self, buffer_file):
|
||||
def begin_playback(self, fd):#buffer_file):
|
||||
self.menuMgr.get_selector_bar().set_spinner(False)
|
||||
uri = "file://" + os.getcwd() +"/" + buffer_file
|
||||
#uri = "file://" + os.getcwd() +"/" + buffer_file
|
||||
#f = open(os.getcwd() +"/" + buffer_file, 'r')
|
||||
uri = "fd://" + str(fd)
|
||||
#print uri
|
||||
self.videoController.play_video(uri, self)
|
||||
|
||||
"""
|
||||
timeline = clutter.Timeline(15, 25)
|
||||
alpha = clutter.Alpha(timeline, clutter.ramp_inc_func)
|
||||
behaviour = clutter.BehaviourOpacity(alpha, 0,255)
|
||||
behaviour.apply(self.video)
|
||||
|
||||
self.stage.add(self.video)
|
||||
self.video.set_playing(True)
|
||||
timeline.start()
|
||||
#return None
|
||||
"""
|
||||
|
||||
def video_size_change(self, texture, width, height):
|
||||
self.video.set_property("sync-size", False)
|
||||
self.video.set_position(0, 0)
|
||||
xy_ratio = float(width / height)
|
||||
print "XY Ratio: " + str(xy_ratio)
|
||||
|
||||
width = int(self.stage.get_width())
|
||||
height = int (width / xy_ratio)
|
||||
height = 768
|
||||
|
||||
self.video.set_size(width, height)
|
||||
|
||||
def stop(self):
|
||||
self.videoController.stop_video()
|
||||
self.myConn.stop() # Stops the backend / frontend streaming
|
||||
|
|
|
@ -15,6 +15,7 @@ class Module():
|
|||
|
||||
def __init__(self, MenuMgr, dbMgr):
|
||||
self.stage = MenuMgr.get_stage()
|
||||
self.MenuMgr = MenuMgr
|
||||
self.cover_viewer = coverViewer(self.stage, 800, 600)
|
||||
self.videoController = VideoController(self.stage)
|
||||
self.is_playing = False
|
||||
|
@ -69,6 +70,11 @@ class Module():
|
|||
|
||||
|
||||
def begin(self, MenuMgr):
|
||||
#Check that the library actually contains something
|
||||
if self.cover_viewer.num_covers == 0:
|
||||
self.MenuMgr.display_msg("Error: No videos", "There are no videos available in the library. This maybe caused by an empty library or a failed connection to the server.")
|
||||
self.stop()
|
||||
return
|
||||
|
||||
#Create a backdrop for the player. In this case we just use the same background as the menus
|
||||
self.backdrop = clutter.CloneTexture(MenuMgr.get_skinMgr().get_Background())
|
||||
|
@ -106,6 +112,8 @@ class Module():
|
|||
timeline_stop.connect('completed', self.destroyPlugin)
|
||||
timeline_stop.start()
|
||||
|
||||
self.MenuMgr.currentPlugin = None
|
||||
|
||||
def destroyPlugin(self, data):
|
||||
self.stage.remove(self.cover_viewer)
|
||||
self.backdrop.hide()
|
||||
|
|
Loading…
Reference in New Issue