diff --git a/fsl/data/strings.py b/fsl/data/strings.py
index 4d0308f80841785124d50930891c50a76d8e98f2..f09013cb6deb6eb80d64d4a6110513745e0eb8f9 100644
--- a/fsl/data/strings.py
+++ b/fsl/data/strings.py
@@ -282,6 +282,8 @@ properties = TypeDict({
     'CanvasPanel.syncLocation'       : 'Sync location',
     'CanvasPanel.syncOverlayOrder'   : 'Sync overlay order',
     'CanvasPanel.syncOverlayDisplay' : 'Sync overlay display settings',
+    'CanvasPanel.movieMode'          : 'Movie mode',
+    'CanvasPanel.movieRate'          : 'Movie update rate',
     'CanvasPanel.profile'            : 'Mode',
 
     'SceneOpts.showCursor'         : 'Show location cursor',
diff --git a/fsl/fslview/controls/canvassettingspanel.py b/fsl/fslview/controls/canvassettingspanel.py
index 82c076ecfe9869702e9bc3266ac4f9d5af308c30..d336ede8e7d33868386f0b8230ce8424113eb663 100644
--- a/fsl/fslview/controls/canvassettingspanel.py
+++ b/fsl/fslview/controls/canvassettingspanel.py
@@ -21,7 +21,9 @@ _CANVASPANEL_PROPS = [
         visibleWhen=lambda i: len(i.getProp('profile').getChoices(i)) > 1), 
     props.Widget('syncOverlayOrder'),
     props.Widget('syncLocation'),
-    props.Widget('syncOverlayDisplay')
+    props.Widget('syncOverlayDisplay'),
+    props.Widget('movieMode'),
+    props.Widget('movieRate', spin=False, showLimits=False),
 ]
 
 _SCENEOPTS_PROPS = [
diff --git a/fsl/fslview/views/canvaspanel.py b/fsl/fslview/views/canvaspanel.py
index ef25c835b9ffcd6b13da26032df564938648aab1..6c308e74f5a356dea0b732ba3e930eaa7d6319bb 100644
--- a/fsl/fslview/views/canvaspanel.py
+++ b/fsl/fslview/views/canvaspanel.py
@@ -167,6 +167,12 @@ class CanvasPanel(viewpanel.ViewPanel):
     syncLocation       = props.Boolean(default=True)
     syncOverlayOrder   = props.Boolean(default=True)
     syncOverlayDisplay = props.Boolean(default=True)
+    movieMode          = props.Boolean(default=False)
+    movieRate          = props.Int(minval=100,
+                                   maxval=2000,
+                                   default=250,
+                                   clamped=True)
+    
 
     def __init__(self,
                  parent,
@@ -224,6 +230,17 @@ class CanvasPanel(viewpanel.ViewPanel):
 
         self.setCentrePanel(self.__canvasContainer)
 
+        # Stores a reference to a wx.Timer
+        # when movie mode is enabled
+        self.__movieTimer    = None
+
+        self.addListener('movieMode',
+                         self._name,
+                         self.__movieModeChanged)
+        self.addListener('movieRate',
+                         self._name,
+                         self.__movieRateChanged)
+
         # Canvas/colour bar layout is managed in
         # the _layout/_toggleColourBar methods
         self.__canvasSizer   = None
@@ -238,10 +255,6 @@ class CanvasPanel(viewpanel.ViewPanel):
         self.__layout()
 
 
-    def getSceneOptions(self):
-        return self.__opts
-
-
     def destroy(self):
         """Makes sure that any remaining control panels are destroyed
         cleanly.
@@ -251,7 +264,11 @@ class CanvasPanel(viewpanel.ViewPanel):
             self.__colourBar.destroy()
             
         viewpanel.ViewPanel.destroy(self)
-            
+
+        
+    def getSceneOptions(self):
+        return self.__opts
+        
     
     def screenshot(self, *a):
         _takeScreenShot(self._overlayList, self._displayCtx, self)
@@ -313,3 +330,48 @@ class CanvasPanel(viewpanel.ViewPanel):
 
         # Force the canvas panel to resize itself
         self.PostSizeEvent()
+
+
+    def __movieModeChanged(self, *a):
+
+        if self.__movieTimer is not None:
+            self.__movieTimer.Stop()
+            self.__movieTimer = None
+
+        if not self.movieMode:
+            return
+        
+        self.__movieTimer = wx.Timer(self)
+        self.Bind(wx.EVT_TIMER, self.__movieUpdate)
+        self.__movieTimer.Start(self.movieRate)
+        
+
+    def __movieRateChanged(self, *a):
+        if not self.movieMode:
+            return
+
+        self.__movieModeChanged()
+
+        
+    def __movieUpdate(self, ev):
+
+        overlay = self._displayCtx.getSelectedOverlay()
+
+        if overlay is None:
+            return
+
+        if not isinstance(overlay, fslimage.Image):
+            return
+
+        if not overlay.is4DImage():
+            return
+
+        opts = self._displayCtx.getOpts(overlay)
+
+        if not isinstance(opts, displayctx.VolumeOpts):
+            return
+
+        limit = overlay.shape[3]
+
+        if opts.volume == limit - 1: opts.volume  = 0
+        else:                        opts.volume += 1