Commit 1dfe3f30 authored by petter's avatar petter
Browse files

Kameraunterstützung Teil 1

git-svn-id: https://www2.in.tum.de/repos/ttt/trunk@31 0463f305-d864-43cb-8a47-61cf597d4139
parent 7e6db57d
......@@ -64,7 +64,7 @@
<fileset dir="${classes}/ttt/resources"/>
<manifest>
<attribute name="Main-Class" value="ttt/TTT" />
<attribute name="Class-Path" value="itext-1.4.8.jar jsch-0.1.32-patched.jar swing-layout-1.0.2.jar jmf-2.1.1e.jar mp3plugin.jar" />
<attribute name="Class-Path" value="itext-1.4.8.jar jsch-0.1.32-patched.jar swing-layout-1.0.2.jar jmf-2.1.1e.jar mp3plugin.jar lti-civil.jar v4l4j.jar" />
</manifest>
</jar>
<copy todir="${dist}"><fileset dir="${lib}"></fileset></copy>
......
......@@ -45,6 +45,7 @@ public class LectureProfile {
private int port = 5900;
private boolean record = true;
private boolean recordVideo = true;
private boolean recordWebcam = true;
private boolean recordLinearAudio = true; // linear = wav
private boolean loopbackRecorder = false;
private int colorDepth = Constants.defaultColorDepth;
......@@ -488,7 +489,7 @@ public class LectureProfile {
public void setRecordVideoEnabled(boolean recordVideo) {
this.recordVideo = recordVideo;
}
public boolean isRecordLinearAudioEnabled() {
return recordLinearAudio;
}
......
......@@ -216,6 +216,13 @@ public class LectureProfileDialog {
recordVideoCheckBox.setOpaque(false);
recordVideoCheckBox.setSelected(true);
recordVideoCheckBox.setEnabled(false);
// cam recording
final JCheckBox camCheckBox = new JCheckBox("incl. Webcam");
camCheckBox.setToolTipText("enable Webcam recoding");
camCheckBox.setOpaque(false);
camCheckBox.setSelected(true);
camCheckBox.setEnabled(false);
// enable/disable according to recorder selection
recorderCheckBox.addActionListener(new ActionListener() {
......@@ -355,6 +362,7 @@ public class LectureProfileDialog {
ButtonGroup videoRecordingButtonGroup = new ButtonGroup();
videoRecordingButtonGroup.add(videoRecordingOnCheckbox);
videoRecordingButtonGroup.add(videoRecordingOffCheckbox);
final JPanel videoRecordingPanel = new JPanel();
videoRecordingPanel.setLayout(new BoxLayout(videoRecordingPanel, BoxLayout.Y_AXIS));
......@@ -374,6 +382,8 @@ public class LectureProfileDialog {
videoRecordingPanel.add(audioFormatLabel);
videoRecordingPanel.add(wavRadioButton);
videoRecordingPanel.add(mp3RadioButton);
videoRecordingPanel.add(Box.createVerticalStrut(5));
......@@ -551,7 +561,7 @@ public class LectureProfileDialog {
hostPortDividerLabel.setEnabled(!loopback);
displayDesktopCheckBox.setSelected(!loopback);
recorderCheckBox.setSelected(profile.isRecordEnabled());
recorderCheckBox.setSelected(profile.isRecordEnabled());
recordVideoCheckBox.setSelected(profile.isRecordVideoEnabled());
recordVideoCheckBox.setVisible(recorderCheckBox.isSelected());
videoRecordingOnCheckbox.setSelected(profile.isRecordVideoEnabled());
......
......@@ -764,7 +764,7 @@ public class PostProcessor extends JPanel {
Insets insets = new Insets(0, 10, 0, 10);
// ////////////////////////////////////////////////
// infomation about recording
// information about recording
// ////////////////////////////////////////////////
final JLabel titleLabel = new JLabel(recording.prefs.name);
......
......@@ -340,6 +340,15 @@ public class PostProcessorPanel extends GradientPanel {
ocrStatusField.setText("not found");
ocrStatusField.setToolTipText(null);
}
if (recording.getExistingFileBySuffix("zip").exists()) {
camStatusField.setForeground(Color.GREEN);
camStatusField.setText("folder found");
camStatusField.setToolTipText("folder exists - content not confirmed");
} else {
camStatusField.setForeground(Color.RED);
camStatusField.setText("not found");
camStatusField.setToolTipText(null);
}
if (recording.getExistingFileBySuffix("mp3").exists()) {
mp3StatusField.setForeground(Color.GREEN);
mp3StatusField.setText("found");
......@@ -475,10 +484,12 @@ public class PostProcessorPanel extends GradientPanel {
pdfStatusField = new javax.swing.JLabel();
ocrStatusField = new javax.swing.JLabel();
flashStatusField = new javax.swing.JLabel();
mp3CheckBox = new javax.swing.JCheckBox();
mp3CheckBox = new javax.swing.JCheckBox();
mp3StatusField = new javax.swing.JLabel();
mp4CheckBox = new javax.swing.JCheckBox();
mp4StatusField = new javax.swing.JLabel();
camCheckBox = new javax.swing.JCheckBox();
camStatusField = new javax.swing.JLabel();
jPanel3 = new javax.swing.JPanel();
jLabel10 = new javax.swing.JLabel();
searchStatusField = new javax.swing.JLabel();
......@@ -625,6 +636,11 @@ public class PostProcessorPanel extends GradientPanel {
flashCheckBox.setText("Flash/SWF");
flashCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
camCheckBox.setSelected(true);
camCheckBox.setText("Cam");
camCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
createButton.setText("Create");
createButton.setMargin(new java.awt.Insets(0, 8, 0, 8));
createButton.addActionListener(new java.awt.event.ActionListener() {
......@@ -676,7 +692,9 @@ public class PostProcessorPanel extends GradientPanel {
.add(ocrCheckBox)
.add(mp3CheckBox)
.add(flashCheckBox)
.add(mp4CheckBox))
.add(mp4CheckBox)
.add(camCheckBox)
)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(ocrStatusField)
......@@ -687,7 +705,9 @@ public class PostProcessorPanel extends GradientPanel {
.add(htmlStatusField)
.add(mp3StatusField)
.add(flashStatusField)
.add(mp4StatusField))
.add(mp4StatusField)
.add(camStatusField)
)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 370, Short.MAX_VALUE)
.add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
.add(createHelpButton)
......@@ -732,6 +752,10 @@ public class PostProcessorPanel extends GradientPanel {
.add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(mp4CheckBox)
.add(mp4StatusField))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(camCheckBox)
.add(camStatusField))
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel2Layout.createSequentialGroup()
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
......@@ -1004,7 +1028,9 @@ public class PostProcessorPanel extends GradientPanel {
htmlCheckBox.setEnabled(enabled);
pdfCheckBox.setEnabled(enabled && ctrlSatus.get(pdfCheckBox)); //---
ocrCheckBox.setEnabled(enabled);
flashCheckBox.setEnabled(enabled && ctrlSatus.get(flashCheckBox)); //---
camCheckBox.setEnabled(enabled);
mp3CheckBox.setEnabled(enabled && ctrlSatus.get(mp3CheckBox)); //---
mp4CheckBox.setEnabled(enabled && ctrlSatus.get(mp4CheckBox)); //---
createHelpButton.setEnabled(enabled);
......@@ -1333,6 +1359,8 @@ public class PostProcessorPanel extends GradientPanel {
mode |= ScriptCreator.PDF_SCRIPT;
if (ocrCheckBox.isSelected())
mode |= ScriptCreator.OCR_OPTIMIZED;
// compute everything specified by mode
recording.createScript(mode, batch);
} catch (Exception e) {
......@@ -1376,6 +1404,18 @@ public class PostProcessorPanel extends GradientPanel {
e.printStackTrace();
}
//create camVid
try {
if (camCheckBox.isSelected()) {
ttt.videoRecorder.VideoCreator newVideo = new ttt.videoRecorder.VideoCreator();
newVideo.create(recording.getExistingFileBySuffix("bjpg").getPath());//TODO convert
}
} catch (Exception e) {
TTT.showMessage("CamVid creation failed: " + e);
e.printStackTrace();
}
// update status fields
updateStatusFields();
......@@ -1490,6 +1530,7 @@ public class PostProcessorPanel extends GradientPanel {
private javax.swing.JButton doneButton;
private javax.swing.JLabel durationField;
private javax.swing.JLabel filenameField;
private javax.swing.JCheckBox camCheckBox;
private javax.swing.JCheckBox flashCheckBox;
private javax.swing.JLabel flashStatusField;
private javax.swing.JCheckBox htmlCheckBox;
......@@ -1519,6 +1560,7 @@ public class PostProcessorPanel extends GradientPanel {
private javax.swing.JLabel mp4StatusField;
private javax.swing.JCheckBox ocrCheckBox;
private javax.swing.JLabel ocrStatusField;
private javax.swing.JLabel camStatusField;
private javax.swing.JButton openSearchbaseFileDialogButton;
private javax.swing.JTextField pathField;
private javax.swing.JCheckBox pdfCheckBox;
......
......@@ -51,6 +51,8 @@ import ttt.messages.DeleteAllAnnotation;
import ttt.messages.Message;
import ttt.messages.MessageConsumer;
import ttt.messages.WhiteboardMessage;
import ttt.videoRecorder.*;
public class Recorder implements MessageConsumer, Closeable {
......@@ -59,7 +61,8 @@ public class Recorder implements MessageConsumer, Closeable {
private DataOutputStream out;
private AudioRecorder audioVideoRecorder;
private VideoRecorder VideoRecorder;
private LectureProfile lectureProfile;
public Recorder(RfbProtocol protocol, LectureProfile lectureProfile) throws IOException {
......@@ -327,6 +330,15 @@ public class Recorder implements MessageConsumer, Closeable {
if (audioVideoRecorder != null)
audioVideoRecorder.startRec(file.getCanonicalPath());
//VideoRecStuff start
// TODO VideoRecStart
if(lectureProfile.isRecordVideoEnabled()){
VideoRecorder = new VideoRecorder();
VideoRecorder.setRecordpath(file.getCanonicalPath().substring(0, file.getCanonicalPath().length()-4));
VideoRecorder.Start();
}
//VideoRecStuff end
// startime
long starttime = System.currentTimeMillis();
new_out.writeLong(starttime);
......@@ -402,6 +414,18 @@ public class Recorder implements MessageConsumer, Closeable {
audioVideoRecorder.stopRec();
}
//TODO VideorecStop
if (VideoRecorder != null) {
if (closing) {
VideoRecorder.close();
VideoRecorder = null;
} else
VideoRecorder.Stop();
}
out.flush();
out.close();
out = null;
......
package ttt.videoRecorder;
/*
* @(#)JpegImagesToMovie.java 1.3 01/03/13
*
* Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
*
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
* modify and redistribute this software in source and binary code form,
* provided that i) this copyright notice and license appear on all copies of
* the software; and ii) Licensee does not utilize the software in a manner
* which is disparaging to Sun.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* This software is not designed or intended for use in on-line control of
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
* the design, construction, operation or maintenance of any nuclear
* facility. Licensee represents and warrants that it will not use or
* redistribute the Software for such purposes.
*/
import java.io.*;
import java.util.*;
import java.awt.Dimension;
import javax.media.*;
import javax.media.control.*;
import javax.media.protocol.*;
import javax.media.datasink.*;
import javax.media.format.VideoFormat;
/**
* This program takes a list of JPEG image files and convert them into
* a QuickTime movie.
*/
public class JpegImagesToMovie implements ControllerListener, DataSinkListener {
@SuppressWarnings("static-access")
public boolean doIt(int width, int height, int frameRate, Vector<byte[]> inFiles, MediaLocator outML) {
ImageDataSource ids = new ImageDataSource(width, height, frameRate, inFiles);
Processor p;
try {
System.err.println("- create processor for the image datasource ...");
p = Manager.createProcessor(ids);
} catch (Exception e) {
System.err.println("Yikes! Cannot create a processor from the data source.");
return false;
}
p.addControllerListener(this);
// Put the Processor into configured state so we can set
// some processing options on the processor.
p.configure();
if (!waitForState(p, p.Configured)) {
System.err.println("Failed to configure the processor.");
return false;
}
// Set the output content descriptor to QuickTime.
p.setContentDescriptor(new ContentDescriptor(FileTypeDescriptor.QUICKTIME));
// Query for the processor for supported formats.
// Then set it on the processor.
TrackControl tcs[] = p.getTrackControls();
Format f[] = tcs[0].getSupportedFormats();
if (f == null || f.length <= 0) {
System.err.println("The mux does not support the input format: " + tcs[0].getFormat());
return false;
}
tcs[0].setFormat(f[0]);
System.err.println("Setting the track format to: " + f[0]);
// We are done with programming the processor. Let's just
// realize it.
p.realize();
if (!waitForState(p, p.Realized)) {
System.err.println("Failed to realize the processor.");
return false;
}
// Now, we'll need to create a DataSink.
DataSink dsink;
if ((dsink = createDataSink(p, outML)) == null) {
System.err.println("Failed to create a DataSink for the given output MediaLocator: " + outML);
return false;
}
dsink.addDataSinkListener(this);
fileDone = false;
System.err.println("start processing...");
// OK, we can now start the actual transcoding.
try {
p.start();
dsink.start();
} catch (IOException e) {
System.err.println("IO error during processing");
return false;
}
// Wait for EndOfStream event.
waitForFileDone();
// Cleanup.
try {
dsink.close();
} catch (Exception e) {}
p.removeControllerListener(this);
System.err.println("...done processing.");
return true;
}
/**
* Create the DataSink.
*/
DataSink createDataSink(Processor p, MediaLocator outML) {
DataSource ds;
if ((ds = p.getDataOutput()) == null) {
System.err.println("Something is really wrong: the processor does not have an output DataSource");
return null;
}
DataSink dsink;
try {
System.err.println("- create DataSink for: " + outML);
dsink = Manager.createDataSink(ds, outML);
dsink.open();
} catch (Exception e) {
System.err.println("Cannot create the DataSink: " + e);
return null;
}
return dsink;
}
Object waitSync = new Object();
boolean stateTransitionOK = true;
/**
* Block until the processor has transitioned to the given state.
* Return false if the transition failed.
*/
boolean waitForState(Processor p, int state) {
synchronized (waitSync) {
try {
while (p.getState() < state && stateTransitionOK)
waitSync.wait();
} catch (Exception e) {}
}
return stateTransitionOK;
}
/**
* Controller Listener.
*/
public void controllerUpdate(ControllerEvent evt) {
if (evt instanceof ConfigureCompleteEvent ||
evt instanceof RealizeCompleteEvent ||
evt instanceof PrefetchCompleteEvent) {
synchronized (waitSync) {
stateTransitionOK = true;
waitSync.notifyAll();
}
} else if (evt instanceof ResourceUnavailableEvent) {
synchronized (waitSync) {
stateTransitionOK = false;
waitSync.notifyAll();
}
} else if (evt instanceof EndOfMediaEvent) {
evt.getSourceController().stop();
evt.getSourceController().close();
}
}
Object waitFileSync = new Object();
boolean fileDone = false;
boolean fileSuccess = true;
/**
* Block until file writing is done.
*/
boolean waitForFileDone() {
synchronized (waitFileSync) {
try {
while (!fileDone)
waitFileSync.wait();
} catch (Exception e) {}
}
return fileSuccess;
}
/**
* Event handler for the file writer.
*/
public void dataSinkUpdate(DataSinkEvent evt) {
if (evt instanceof EndOfStreamEvent) {
synchronized (waitFileSync) {
fileDone = true;
waitFileSync.notifyAll();
}
} else if (evt instanceof DataSinkErrorEvent) {
synchronized (waitFileSync) {
fileDone = true;
fileSuccess = false;
waitFileSync.notifyAll();
}
}
}
@SuppressWarnings("unchecked")
public static void main(String args[]) {
if (args.length == 0)
prUsage();
// Parse the arguments.
int i = 0;
int width = -1, height = -1, frameRate = 1;
Vector inputFiles = new Vector();
String outputURL = null;
while (i < args.length) {
if (args[i].equals("-w")) {
i++;
if (i >= args.length)
prUsage();
width = new Integer(args[i]).intValue();
} else if (args[i].equals("-h")) {
i++;
if (i >= args.length)
prUsage();
height = new Integer(args[i]).intValue();
} else if (args[i].equals("-f")) {
i++;
if (i >= args.length)
prUsage();
frameRate = new Integer(args[i]).intValue();
} else if (args[i].equals("-o")) {
i++;
if (i >= args.length)
prUsage();
outputURL = args[i];
} else {
inputFiles.addElement(args[i]);
}
i++;
}
if (outputURL == null || inputFiles.size() == 0)
prUsage();
// Check for output file extension.
if (!outputURL.endsWith(".mov") && !outputURL.endsWith(".MOV")) {
System.err.println("The output file extension should end with a .mov extension");
prUsage();
}
if (width < 0 || height < 0) {
System.err.println("Please specify the correct image size.");
prUsage();
}
// Check the frame rate.
if (frameRate < 1)
frameRate = 1;
// Generate the output media locators.
MediaLocator oml;
if ((oml = createMediaLocator(outputURL)) == null) {
System.err.println("Cannot build media locator from: " + outputURL);
System.exit(0);
}
JpegImagesToMovie imageToMovie = new JpegImagesToMovie();
imageToMovie.doIt(width, height, frameRate, inputFiles, oml);
System.exit(0);
}
static void prUsage() {
System.err.println("Usage: java JpegImagesToMovie -w <width> -h <height> -f <frame rate> -o <output URL> <input JPEG file 1> <input JPEG file 2> ...");
System.exit(-1);
}
/**
* Create a media locator from the given string.
*/
static MediaLocator createMediaLocator(String url) {
MediaLocator ml;
if (url.indexOf(":") > 0 && (ml = new MediaLocator(url)) != null)
return ml;
if (url.startsWith(File.separator)) {
if ((ml = new MediaLocator("file:" + url)) != null)
return ml;
} else {
String file = "file:" + System.getProperty("user.dir") + File.separator + url;
if ((ml = new MediaLocator(file)) != null)
return ml;
}
return null;
}
///////////////////////////////////////////////
//
// Inner classes.
///////////////////////////////////////////////
/**
* A DataSource to read from a list of JPEG image files and
* turn that into a stream of JMF buffers.
* The DataSource is not seekable or positionable.
*/