View Javadoc

1   /**
2    * Copyright (c) 2011, The University of Southampton and the individual contributors.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    *
8    *   * 	Redistributions of source code must retain the above copyright notice,
9    * 	this list of conditions and the following disclaimer.
10   *
11   *   *	Redistributions in binary form must reproduce the above copyright notice,
12   * 	this list of conditions and the following disclaimer in the documentation
13   * 	and/or other materials provided with the distribution.
14   *
15   *   *	Neither the name of the University of Southampton nor the names of its
16   * 	contributors may be used to endorse or promote products derived from this
17   * 	software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.openimaj.content.slideshow;
31  
32  import java.awt.Component;
33  import java.awt.Dimension;
34  import java.awt.event.KeyEvent;
35  import java.awt.event.KeyListener;
36  import java.awt.image.BufferedImage;
37  import java.io.File;
38  import java.io.IOException;
39  import java.net.URL;
40  
41  import org.apache.commons.io.FileUtils;
42  import org.openimaj.image.DisplayUtilities.ImageComponent;
43  import org.openimaj.image.ImageUtilities;
44  import org.openimaj.image.MBFImage;
45  import org.openimaj.image.processing.transform.MBFProjectionProcessor;
46  import org.openimaj.video.VideoDisplay;
47  import org.openimaj.video.VideoDisplay.EndAction;
48  import org.openimaj.video.VideoDisplayListener;
49  import org.openimaj.video.xuggle.XuggleVideo;
50  
51  import Jama.Matrix;
52  
53  /**
54   * Slide that shows a video. Number keys are bound to seek to different points
55   * in the video.
56   *
57   * @author Sina Samangooei (ss@ecs.soton.ac.uk)
58   *
59   */
60  public class VideoSlide implements Slide, VideoDisplayListener<MBFImage>, KeyListener {
61  	URL url;
62  	VideoDisplay<MBFImage> display;
63  	private URL background;
64  	protected PictureSlide pictureSlide;
65  	private final Matrix transform;
66  	private ImageComponent panel;
67  	private BufferedImage bimg;
68  	private MBFImage mbfImage;
69  	private XuggleVideo video;
70  	private EndAction endAction = EndAction.LOOP;
71  
72  	/**
73  	 * Default constructor.
74  	 *
75  	 * @param video
76  	 * @param background
77  	 * @param transform
78  	 * @param endAction
79  	 * @throws IOException
80  	 */
81  	public VideoSlide(final URL video, final URL background, final Matrix transform, EndAction endAction)
82  			throws IOException
83  	{
84  		this.url = makeURL(video);
85  		this.background = background;
86  		this.pictureSlide = new PictureSlide(this.background);
87  		this.transform = transform;
88  		this.endAction = endAction;
89  	}
90  
91  	/**
92  	 * Default constructor.
93  	 *
94  	 * @param video
95  	 * @param transform
96  	 * @param endAction
97  	 * @throws IOException
98  	 */
99  	public VideoSlide(final URL video, final Matrix transform, EndAction endAction) throws IOException {
100 		this.url = makeURL(video);
101 		this.transform = transform;
102 		this.endAction = endAction;
103 	}
104 
105 	private URL makeURL(URL url) throws IOException {
106 		if (url.getProtocol().startsWith("jar")) {
107 			final File tmp = File.createTempFile("movie", ".tmp");
108 			tmp.deleteOnExit();
109 			FileUtils.copyURLToFile(url, tmp);
110 			url = tmp.toURI().toURL();
111 		}
112 		return url;
113 	}
114 
115 	/**
116 	 * Default constructor.
117 	 *
118 	 * @param video
119 	 * @param background
120 	 * @param endAction
121 	 * @throws IOException
122 	 */
123 	public VideoSlide(final URL video, final URL background, EndAction endAction) throws IOException {
124 		this(video, background, null, endAction);
125 	}
126 
127 	@Override
128 	public Component getComponent(final int width, final int height) throws IOException {
129 		if (this.pictureSlide == null) {
130 			this.mbfImage = new MBFImage(width, height, 3);
131 			this.panel = (ImageComponent) new PictureSlide(this.mbfImage).getComponent(width, height);
132 		}
133 		else {
134 			this.panel = (ImageComponent) this.pictureSlide.getComponent(width, height);
135 			this.mbfImage = this.pictureSlide.mbfImage.clone();
136 		}
137 
138 		this.panel.setSize(width, height);
139 		this.panel.setPreferredSize(new Dimension(width, height));
140 
141 		this.video = new XuggleVideo(this.url, false);
142 		this.display = VideoDisplay.createOffscreenVideoDisplay(this.video);
143 		this.display.setEndAction(this.endAction);
144 
145 		this.display.addVideoListener(this);
146 
147 		return this.panel;
148 	}
149 
150 	@Override
151 	public void close() {
152 		this.display.close();
153 	}
154 
155 	@Override
156 	public void afterUpdate(final VideoDisplay<MBFImage> display) {
157 		// do nothing
158 	}
159 
160 	@Override
161 	public void beforeUpdate(final MBFImage frame) {
162 		if (this.transform != null) {
163 			final MBFImage bgCopy = this.mbfImage.clone();
164 			final MBFProjectionProcessor proj = new MBFProjectionProcessor();
165 			proj.setMatrix(this.transform);
166 			proj.accumulate(frame);
167 			proj.performProjection(0, 0, bgCopy);
168 			this.panel.setImage(this.bimg = ImageUtilities.createBufferedImageForDisplay(bgCopy, this.bimg));
169 		}
170 		else
171 			this.panel.setImage(this.bimg = ImageUtilities.createBufferedImageForDisplay(frame, this.bimg));
172 	}
173 
174 	@Override
175 	public void keyPressed(final KeyEvent key) {
176 		final int code = key.getKeyCode();
177 		if (code >= KeyEvent.VK_0 && code <= KeyEvent.VK_9) {
178 			final double prop = (code - KeyEvent.VK_0) / 10.0;
179 			final long dur = this.video.getDuration();
180 			this.display.seek((long) (dur * prop));
181 		}
182 		if (code == KeyEvent.VK_SPACE) {
183 			this.display.togglePause();
184 		}
185 	}
186 
187 	@Override
188 	public void keyReleased(final KeyEvent arg0) {
189 		// do nothing
190 	}
191 
192 	@Override
193 	public void keyTyped(final KeyEvent arg0) {
194 		// do nothing
195 	}
196 }