From a3351b2c66d42ed2c398269c926885e20555a4c0 Mon Sep 17 00:00:00 2001 From: noisymime Date: Thu, 22 Nov 2007 10:41:29 +0000 Subject: [PATCH] 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. --- MenuMgr.py | 113 +++++++++++++++++++++- MenuMgr.pyc | Bin 7519 -> 10871 bytes VideoController.py | 34 +++++-- modules/myth_tv_player/MythBackendConn.py | 26 ++--- modules/myth_tv_player/myth_tv_player.py | 31 +----- modules/video_player/cover_viewer.py | 2 +- modules/video_player/video_player.py | 8 ++ 7 files changed, 166 insertions(+), 48 deletions(-) diff --git a/MenuMgr.py b/MenuMgr.py index c72bc36..5149062 100644 --- a/MenuMgr.py +++ b/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: @@ -153,6 +165,9 @@ class MenuMgr: if len(self.menuHistory)>1: 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 @@ -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() \ No newline at end of file diff --git a/MenuMgr.pyc b/MenuMgr.pyc index 570d83838fb8c175debc924fe293442284244d34..216bbe667e0288821e16ba97143c680d557e016b 100644 GIT binary patch literal 10871 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 diff --git a/VideoController.py b/VideoController.py index a39a371..7c82103 100644 --- a/VideoController.py +++ b/VideoController.py @@ -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") diff --git a/modules/myth_tv_player/MythBackendConn.py b/modules/myth_tv_player/MythBackendConn.py index f8f94b9..6021000 100644 --- a/modules/myth_tv_player/MythBackendConn.py +++ b/modules/myth_tv_player/MythBackendConn.py @@ -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 diff --git a/modules/myth_tv_player/myth_tv_player.py b/modules/myth_tv_player/myth_tv_player.py index aa96af6..99d0fae 100644 --- a/modules/myth_tv_player/myth_tv_player.py +++ b/modules/myth_tv_player/myth_tv_player.py @@ -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 diff --git a/modules/video_player/cover_viewer.py b/modules/video_player/cover_viewer.py index 1af2e93..22258e8 100644 --- a/modules/video_player/cover_viewer.py +++ b/modules/video_player/cover_viewer.py @@ -131,7 +131,7 @@ class coverViewer(clutter.Group): self.timeline.start() - def select_first(self): + def select_first(self): self.timeline = clutter.Timeline(20,80) self.current_video_details.set_video(self.videoLibrary[0], self.timeline) diff --git a/modules/video_player/video_player.py b/modules/video_player/video_player.py index 9e984f2..c57b5e7 100644 --- a/modules/video_player/video_player.py +++ b/modules/video_player/video_player.py @@ -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()) @@ -105,6 +111,8 @@ class Module(): self.stop_behaviour.apply(self.backdrop) timeline_stop.connect('completed', self.destroyPlugin) timeline_stop.start() + + self.MenuMgr.currentPlugin = None def destroyPlugin(self, data): self.stage.remove(self.cover_viewer)