From e52b3274819d5b64f68fcd21dcd8667622542286 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 23 Jul 2008 19:40:19 +0000 Subject: Restore P-I-P in video playback mode --- diff --git a/glivex.py b/glivex.py new file mode 100644 index 0000000..d28996e --- /dev/null +++ b/glivex.py @@ -0,0 +1,144 @@ +#Copyright (c) 2008, Media Modifications Ltd. + +#Permission is hereby granted, free of charge, to any person obtaining a copy +#of this software and associated documentation files (the "Software"), to deal +#in the Software without restriction, including without limitation the rights +#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +#copies of the Software, and to permit persons to whom the Software is +#furnished to do so, subject to the following conditions: + +#The above copyright notice and this permission notice shall be included in +#all copies or substantial portions of the Software. + +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +#THE SOFTWARE. + +# This class is a cut-down version of glive which uses an ximagesink +# rather than an xvimagesink. This is used in video playback mode, where +# our only Xv port is used for Theora playback. +# +# I tried to modify the glive pipeline to allow swapping an xvimagesink for +# an ximagesink and vice-versa, but that didn't work out (all kinds of strange +# behaviour, perhaps a gstreamer bug). So we resort to using a separate +# pipeline - ugly, but it works... + +import os +import gtk +import pygtk +pygtk.require('2.0') +import sys +import gst +import gst.interfaces +import pygst +pygst.require('0.10') +import time +import threading +import gobject +gobject.threads_init() + +from instance import Instance +from constants import Constants +import record +import utils +import ui + +class GliveX: + def __init__(self, pca): + self.window = None + self.ca = pca + + self.playing = False + + self.pipeline = gst.Pipeline("slow-pipeline") + self.createPipeline() + + bus = self.pipeline.get_bus() + bus.enable_sync_message_emission() + bus.add_signal_watch() + self.SYNC_ID = bus.connect('sync-message::element', self._onSyncMessageCb) + self.MESSAGE_ID = bus.connect('message', self._onMessageCb) + + def createPipeline ( self ): + src = gst.element_factory_make("v4l2src", "camsrc") + try: + # old gst-plugins-good does not have this property + src.set_property("queue-size", 2) + except: + pass + + queue = gst.element_factory_make("queue", "dispqueue") + scale = gst.element_factory_make("videoscale", "scale") + scalecaps = gst.Caps('video/x-raw-yuv,width='+str(ui.UI.dim_PIPW)+',height='+str(ui.UI.dim_PIPH)) + colorspace = gst.element_factory_make("ffmpegcolorspace", "colorspace") + xsink = gst.element_factory_make("ximagesink", "xsink") + self.pipeline.add(src, queue, scale, colorspace, xsink) + gst.element_link_many(src, queue, scale) + scale.link(colorspace, scalecaps) + colorspace.link(xsink) + + def play(self): + self.pipeline.set_state(gst.STATE_PLAYING) + self.playing = True + + def pause(self): + self.pipeline.set_state(gst.STATE_PAUSED) + self.playing = False + + def stop(self): + self.pipeline.set_state(gst.STATE_NULL) + self.playing = False + + def is_playing(self): + return self.playing + + def idlePlayElement(self, element): + element.set_state(gst.STATE_PLAYING) + return False + + def _onSyncMessageCb(self, bus, message): + if message.structure is None: + return + if message.structure.get_name() == 'prepare-xwindow-id': + self.window.set_sink(message.src) + message.src.set_property('force-aspect-ratio', True) + + def _onMessageCb(self, bus, message): + t = message.type + if t == gst.MESSAGE_EOS: + #print("MESSAGE_EOS") + pass + elif t == gst.MESSAGE_ERROR: + #todo: if we come out of suspend/resume with errors, then get us back up and running... + #todo: handle "No space left on the resource.gstfilesink.c" + #err, debug = message.parse_error() + pass + +class SlowLiveVideoWindow(gtk.Window): + def __init__(self, bgd ): + gtk.Window.__init__(self) + + self.imagesink = None + self.glivex = None + + self.modify_bg( gtk.STATE_NORMAL, bgd ) + self.modify_bg( gtk.STATE_INSENSITIVE, bgd ) + self.unset_flags(gtk.DOUBLE_BUFFERED) + self.set_flags(gtk.APP_PAINTABLE) + + def set_glivex(self, pglivex): + self.glivex = pglivex + self.glivex.window = self + + def set_sink(self, sink): + if (self.imagesink != None): + assert self.window.xid + self.imagesink = None + del self.imagesink + + self.imagesink = sink + self.imagesink.set_xwindow_id(self.window.xid) diff --git a/record.py b/record.py index 9c1db56..92a5fcf 100755 --- a/record.py +++ b/record.py @@ -37,6 +37,7 @@ from model import Model from ui import UI from recordtube import RecordTube from glive import Glive +from glivex import GliveX from gplay import Gplay from greplay import Greplay from recorded import Recorded @@ -74,6 +75,7 @@ class Record(activity.Activity): #the main classes self.m = Model(self) self.glive = Glive(self) + self.glivex = GliveX(self) self.gplay = Gplay() self.ui = UI(self) @@ -131,6 +133,7 @@ class Record(activity.Activity): self.m.doShutter() else: self.glive.stop() + self.glivex.stop() def restartPipes(self): @@ -153,6 +156,8 @@ class Record(activity.Activity): self.gplay.stop( ) if (self.glive != None): self.glive.stop( ) + if (self.glivex != None): + self.glivex.stop( ) #this calls write_file activity.Activity.close( self ) diff --git a/ui.py b/ui.py index 3e6cc5a..fc8a53c 100644 --- a/ui.py +++ b/ui.py @@ -50,6 +50,7 @@ from p5_button import P5Button from p5_button import Polygon from p5_button import Button from glive import LiveVideoWindow +from glivex import SlowLiveVideoWindow from gplay import PlayVideoWindow from recorded import Recorded from button import RecdButton @@ -401,12 +402,13 @@ class UI: self.liveVideoWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK) self.liveVideoWindow.connect("visibility-notify-event", self._visibleNotifyCb) - self.returnToLiveWindow = ReturnToLiveWindow() - self.addToWindowStack( self.returnToLiveWindow, self.windowStack[len(self.windowStack)-1] ) - self.returnToLiveWindow.set_events(gtk.gdk.BUTTON_RELEASE_MASK) - self.returnToLiveWindow.connect("button_release_event", self._returnButtonReleaseCb) - self.returnToLiveWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK) - self.returnToLiveWindow.connect("visibility-notify-event", self._visibleNotifyCb) + self.slowLiveVideoWindow = SlowLiveVideoWindow(Constants.colorBlack.gColor) + self.addToWindowStack( self.slowLiveVideoWindow, self.windowStack[len(self.windowStack)-1] ) + self.slowLiveVideoWindow.set_glivex(self.ca.glivex) + self.slowLiveVideoWindow.set_events(gtk.gdk.BUTTON_RELEASE_MASK) + self.slowLiveVideoWindow.connect("button_release_event", self._returnButtonReleaseCb) + self.slowLiveVideoWindow.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK) + self.slowLiveVideoWindow.connect("visibility-notify-event", self._visibleNotifyCb) self.recordWindow = RecordWindow(self) self.addToWindowStack( self.recordWindow, self.windowStack[len(self.windowStack)-1] ) @@ -544,7 +546,7 @@ class UI: self.moveWinOffscreen( self.maxWindow ) self.moveWinOffscreen( self.pipBgdWindow ) self.moveWinOffscreen( self.infWindow ) - self.moveWinOffscreen( self.returnToLiveWindow ) + self.moveWinOffscreen( self.slowLiveVideoWindow ) if (self.FULLSCREEN): self.moveWinOffscreen( self.recordWindow ) @@ -834,6 +836,7 @@ class UI: def _returnButtonReleaseCb(self, widget, event): self.ca.gplay.stop() + self.ca.glivex.stop() self.ca.glive.play() self.resumeLiveVideo() @@ -1327,7 +1330,7 @@ class UI: pos.append({"position":"inf", "window":self.infWindow} ) elif (self.ca.m.MODE == Constants.MODE_VIDEO): pos.append({"position":"pgd", "window":self.pipBgdWindow} ) - pos.append({"position":"pip", "window":self.returnToLiveWindow} ) + pos.append({"position":"pip", "window":self.slowLiveVideoWindow} ) pos.append({"position":"inb", "window":self.playOggWindow} ) pos.append({"position":"inf", "window":self.infWindow} ) elif (self.ca.m.MODE == Constants.MODE_AUDIO): @@ -1359,7 +1362,7 @@ class UI: else: pos.append({"position":"img", "window":self.playOggWindow} ) pos.append({"position":"pgd", "window":self.pipBgdWindow} ) - pos.append({"position":"pip", "window":self.returnToLiveWindow} ) + pos.append({"position":"pip", "window":self.slowLiveVideoWindow} ) if (not self.MESHING): pos.append({"position":"max", "window":self.maxWindow} ) pos.append({"position":"scr", "window":self.scrubWindow} ) @@ -1421,7 +1424,7 @@ class UI: elif (self.ca.m.MODE == Constants.MODE_VIDEO): if (not self.LIVEMODE): pos.append({"position":"pgd", "window":self.pipBgdWindow} ) - pos.append({"position":"pip", "window":self.returnToLiveWindow} ) + pos.append({"position":"pip", "window":self.slowLiveVideoWindow} ) if (not self.MESHING): pos.append({"position":"max", "window":self.maxWindow} ) pos.append({"position":"scr", "window":self.scrubWindow} ) @@ -1638,6 +1641,7 @@ class UI: mediaFilepath = recd.getMediaFilepath() if (mediaFilepath != None): self.ca.glive.stop() + self.ca.glivex.play() videoUrl = "file://" + str( mediaFilepath ) self.ca.gplay.setLocation(videoUrl) self.scrubWindow.doPlay() @@ -1646,6 +1650,7 @@ class UI: if (not ableToShowVideo): # FIXME is this correct? self.ca.glive.stop() + self.ca.glivex.play() thumbFilepath = recd.getThumbFilepath( ) thumbUrl = "file://" + str( thumbFilepath ) self.ca.gplay.setLocation(thumbUrl) @@ -1817,12 +1822,6 @@ class xoPanel(P5): self.xoGuy.render_cairo( ctx ) -class ReturnToLiveWindow(gtk.Window): - def __init__(self): - gtk.Window.__init__(self) - self.add(gtk.Label("Back")) - - class ScrubberWindow(gtk.Window): def __init__(self, ui): gtk.Window.__init__(self) -- cgit v0.9.1