001: /*
002: * Jacareto Copyright (c) 2002-2005
003: * Applied Computer Science Research Group, Darmstadt University of
004: * Technology, Institute of Mathematics & Computer Science,
005: * Ludwigsburg University of Education, and Computer Based
006: * Learning Research Group, Aachen University. All rights reserved.
007: *
008: * Jacareto is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * Jacareto is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public
019: * License along with Jacareto; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: package jacareto.record;
025:
026: import jacareto.cleverphl.gui.InfoDialog;
027: import jacareto.system.Environment;
028:
029: import java.io.IOException;
030:
031: import java.net.MalformedURLException;
032:
033: import javax.media.ControllerEvent;
034: import javax.media.ControllerListener;
035: import javax.media.Duration;
036: import javax.media.Manager;
037: import javax.media.MediaLocator;
038: import javax.media.NoPlayerException;
039: import javax.media.Player;
040: import javax.media.PrefetchCompleteEvent;
041: import javax.media.RealizeCompleteEvent;
042: import javax.media.Time;
043:
044: /**
045: * Represents a VideoClip.
046: *
047: * @author Oliver Specht
048: * @version $revision$
049: */
050: public class VideoClipRecordable extends MediaClipRecordable implements
051: ControllerListener {
052: public static final int DEFAULT_WIDTH = 200;
053: public static final int DEFAULT_HEIGHT = 200;
054:
055: /** The duration */
056: long duration = 0;
057:
058: /** The x position of the video window. */
059: private int x;
060:
061: /** The y position of the video window. */
062: private int y;
063:
064: /** The width of the video window. */
065: private int width;
066:
067: /** The height of the video window. */
068: private int height;
069:
070: /** Automatic size detection. */
071: private boolean hasAutomaticSizeDetection;
072:
073: /**
074: * A video player to determine the duration of the clip. Workaround because to determine the
075: * duration of a Quicktime movie, the player has to have a ceratain state.
076: */
077: private transient Player videoPlayer = null;
078:
079: /**
080: * Creates a new video clip recordable.
081: *
082: * @param env the environment
083: * @param filename the name of the audio file
084: * @param x the x coordinate of the video window
085: * @param y the y coordinate of the video window
086: * @param width the width of the video window
087: * @param height the height of the video window
088: * @param hasAutomaticSizeDetection whether or not the size of the window is set automatically
089: */
090: public VideoClipRecordable(Environment env, String filename, int x,
091: int y, int width, int height,
092: boolean hasAutomaticSizeDetection) {
093: super (env);
094: setFilename(filename);
095: setX(x);
096: setY(y);
097: setWidth(width);
098: setHeight(height);
099: setAutomaticSizeDetection(hasAutomaticSizeDetection);
100: determineDuration();
101: }
102:
103: /**
104: * Creates a new video clip recordable with no file reference.
105: *
106: * @param env Environment
107: * @param x the x coordinate of the video window
108: * @param y the y coordinate of the video window
109: * @param width the width of the video window
110: * @param height the height of the video window
111: * @param hasAutomaticSizeDetection whether or not the size of the window is set automatically
112: */
113: public VideoClipRecordable(Environment env, int x, int y,
114: int width, int height, boolean hasAutomaticSizeDetection) {
115: this (env, "", x, y, width, height, hasAutomaticSizeDetection);
116: }
117:
118: /**
119: * Creates a new video clip recordable with no file reference an no coordinates.
120: *
121: * @param env Environment
122: */
123: public VideoClipRecordable(Environment env) {
124: this (env, "", 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, true);
125: }
126:
127: /**
128: * Creates a new VideoClipRecordable
129: */
130: public VideoClipRecordable() {
131: this (null);
132: }
133:
134: /**
135: * Sets the x coordinate of the video window.
136: *
137: * @param x the new x coordinate
138: */
139: public void setX(int x) {
140: this .x = x;
141: fireValuesChanged();
142: }
143:
144: /**
145: * Sets the y coordinate of the video window.
146: *
147: * @param y the new y coordinate
148: */
149: public void setY(int y) {
150: this .y = y;
151: fireValuesChanged();
152: }
153:
154: /**
155: * Sets the width of the video window.
156: *
157: * @param width the new width
158: */
159: public void setWidth(int width) {
160: this .width = width;
161: fireValuesChanged();
162: }
163:
164: /**
165: * Sets the height of the video window.
166: *
167: * @param height the new height
168: */
169: public void setHeight(int height) {
170: this .height = height;
171: fireValuesChanged();
172: }
173:
174: /**
175: * Sets whether or not the size of the window is set automatically.
176: *
177: * @param hasAutomaticSizeDetection <code>true</code> when the size of the window should be
178: * determined automatically
179: */
180: public void setAutomaticSizeDetection(
181: boolean hasAutomaticSizeDetection) {
182: this .hasAutomaticSizeDetection = hasAutomaticSizeDetection;
183: fireValuesChanged();
184: }
185:
186: /**
187: * Returns the x coordinate of the video window.
188: *
189: * @return the x coordinate
190: */
191: public int getX() {
192: return x;
193: }
194:
195: /**
196: * Returns the y coordinate of the video window.
197: *
198: * @return the y coordinate
199: */
200: public int getY() {
201: return y;
202: }
203:
204: /**
205: * Returns the width of the video window.
206: *
207: * @return the width
208: */
209: public int getWidth() {
210: return width;
211: }
212:
213: /**
214: * Returns the height of the video window.
215: *
216: * @return the height
217: */
218: public int getHeight() {
219: return height;
220: }
221:
222: /**
223: * Returns whether or not the window size is determined automatically.
224: *
225: * @return <code>true</code> if the size is determined automatically
226: */
227: public boolean hasAutomaticSizeDetection() {
228: return hasAutomaticSizeDetection;
229: }
230:
231: /**
232: * Determines the duration of a video file. If the video can't be displayed, an exception
233: * occurs!
234: *
235: * @return true, if the duration could be determined
236: */
237: public boolean determineDuration() {
238: if (!this
239: .getFilename()
240: .equals(
241: getLanguage()
242: .getString(
243: "Recordables.MediaClipRecordable.DefaultFilename"))) {
244: try {
245: // create video player
246: videoPlayer = Manager.createPlayer(new MediaLocator(
247: "file:" + filename));
248: } catch (MalformedURLException e) {
249: InfoDialog dialog;
250: dialog = new InfoDialog(
251: getLanguage().getString(
252: "CleverPHL.InfoDialog.Title"),
253: getLanguage()
254: .getString(
255: "Recordables.MediaClipRecordable.ErrorUnsupportedFileFormat"));
256: dialog.setModal(true);
257: dialog
258: .setTitle(getLanguage()
259: .getString(
260: "Recordables.MediaClipRecordable.ErrorUnsupportedFileFormatTitle"));
261: dialog.setVisible(true);
262:
263: return false;
264: } catch (NoPlayerException e) {
265: InfoDialog dialog;
266: dialog = new InfoDialog(
267: getLanguage().getString(
268: "CleverPHL.InfoDialog.Title"),
269: getLanguage()
270: .getString(
271: "Recordables.MediaClipRecordable.ErrorUnsupportedFileFormat"));
272: dialog.setModal(true);
273: dialog
274: .setTitle(getLanguage()
275: .getString(
276: "Recordables.MediaClipRecordable.ErrorUnsupportedFileFormatTitle"));
277: dialog.setVisible(true);
278:
279: return false;
280: } catch (IOException e) {
281: InfoDialog dialog;
282: dialog = new InfoDialog(
283: getLanguage().getString(
284: "CleverPHL.InfoDialog.Title"),
285: getLanguage()
286: .getString(
287: "Recordables.MediaClipRecordable.ErrorIO"));
288: dialog.setModal(true);
289: dialog
290: .setTitle(getLanguage()
291: .getString(
292: "Recordables.MediaClipRecordable.ErrorIOTitle"));
293: dialog.setVisible(true);
294:
295: return false;
296: }
297:
298: videoPlayer.addControllerListener(this );
299: videoPlayer.realize();
300:
301: return true;
302: }
303:
304: return false;
305: }
306:
307: /**
308: * {@inheritDoc}
309: */
310: public long getDuration() {
311: return this .duration;
312: }
313:
314: /**
315: * {@inheritDoc}
316: */
317: public String getElementName() {
318: return this .getFilename();
319: }
320:
321: /**
322: * {@inheritDoc}
323: */
324: public String getElementDescription() {
325: return "Video Clip";
326: }
327:
328: /**
329: * {@inheritDoc}
330: */
331: public void setDuration(long duration) {
332: this .duration = duration;
333: fireValuesChanged();
334: }
335:
336: /**
337: * {@inheritDoc}
338: */
339: public String toShortString() {
340: return "Video Clip";
341: }
342:
343: /**
344: * VideoClips don't have a processing time, because they are being replayed by the {@link
345: * jacareto.replay.MediaClipReplayer} which handles the processing etc.
346: *
347: * @return boolean false
348: */
349: public boolean hasProcTime() {
350: return false;
351: }
352:
353: public void controllerUpdate(ControllerEvent event) {
354: if (event instanceof RealizeCompleteEvent) {
355: videoPlayer.prefetch();
356: } else if (event instanceof PrefetchCompleteEvent) {
357: Time duration = videoPlayer.getDuration();
358:
359: if ((duration != Duration.DURATION_UNKNOWN)
360: || (duration != Duration.DURATION_UNBOUNDED)) {
361: this .setDuration((long) duration.getSeconds() * 1000);
362: }
363: }
364: }
365: }
|