/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package webcamstudio.media.renderer;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PushbackInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import static webcamstudio.WebcamStudio.audioFreq;
import webcamstudio.mixers.Frame;
import webcamstudio.mixers.WSImage;
import webcamstudio.streams.SourceMovie;
import webcamstudio.streams.SourceMusic;
import webcamstudio.streams.Stream;
import webcamstudio.util.Tools;
/**
*
* @author patrick (modified by karl)
*
* Capturer is used to read output from a running process, and capture audio or video data within that output.
* The data is passed over a TCP socket.
* Presently Capturer reads this data only when instructed to do so by
* an outside caller, but it should be changed to run as a thread and
* read in new data as soon as it's available.
*/
public class Capturer {
private int vport = 0;
private int aport = 0;
private Stream stream;
private ServerSocket videoServer = null;
private ServerSocket audioServer = null;
private WSImage image = null;
private byte[] audio = null;
private Frame frame = null;
private DataInputStream videoIn = null;
private DataInputStream audioIn = null;
private DataInputStream fakeVideoIn = null;
private DataInputStream fakeAudioIn = null;
private boolean noVideoPres = true;
private boolean noAudioPres = true;
private boolean vPauseFlag = false;
private boolean aPauseFlag = false;
private int streamTotalEnd = 0;
private int totalPauseTime = 0;
private int streamEndTime = 0;
private int currTime = 0;
private int pauseTime = 0;
public Capturer(Stream s) {
stream = s;
frame = new Frame(stream.getCaptureWidth(), stream.getCaptureHeight(), stream.getRate());
image = new WSImage(stream.getCaptureWidth(), stream.getCaptureHeight(), BufferedImage.TYPE_INT_RGB);
audio = new byte[(audioFreq * 2 * 2) / stream.getRate()];
frame.setID(stream.getID());
if (stream.hasAudio()) {
try {
audioServer = new ServerSocket(0);
aport = audioServer.getLocalPort();
} catch (IOException ex) {
Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, ex);
}
}
if (!stream.isOnlyAudio()) {
try {
videoServer = new ServerSocket(0);
vport = videoServer.getLocalPort();
} catch (IOException ex) {
Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, ex);
}
}
if (!stream.isOnlyAudio()) {
Thread vCapture = new Thread(new Runnable() {
@Override
public void run() {
try {
Socket connection = videoServer.accept();
System.out.println(stream.getName() + " Video accepted...");
String duration = stream.getStreamTime();
if (stream.hasFakeVideo()) {
fakeVideoIn = new DataInputStream(new BufferedInputStream(connection.getInputStream(), 4096));
}
do {
Tools.sleep(20);
if (fakeAudioIn != null) {
if (fakeAudioIn.available() != 0) {
noVideoPres=false;
Tools.sleep(stream.getVDelay());
videoIn = fakeVideoIn;
if (!duration.equals("N/A")) {
int millisDuration = Integer.parseInt(duration.replace("s", ""))*1000;
streamEndTime = (int) System.currentTimeMillis() + millisDuration;
streamTotalEnd = streamEndTime;
}
System.out.println("Start Video ...");
}
} else if (stream.getName().contains("Desktop")) {
noVideoPres=false;
Tools.sleep(stream.getVDelay());
videoIn = new DataInputStream(new BufferedInputStream(connection.getInputStream(), 4096));
System.out.println("Start Dekstop Video ...");
} else if (stream.getClass().getName().contains("SourceWebcam")) {
noVideoPres=false;
Tools.sleep(stream.getVDelay());
videoIn = new DataInputStream(new BufferedInputStream(connection.getInputStream(), 4096));
System.out.println("Start Webcam Video ...");
} else if (!stream.hasAudio()) {
noVideoPres=false;
Tools.sleep(stream.getVDelay());
videoIn = fakeVideoIn;
if (!duration.equals("N/A")) {
int millisDuration = Integer.parseInt(stream.getStreamTime().replace("s", ""))*1000;
streamEndTime = (int) System.currentTimeMillis() + millisDuration;
streamTotalEnd = streamEndTime;
}
System.out.println("Start NoAudio Video ...");
}
} while (noVideoPres);
} catch (IOException ex) {
Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
vCapture.setPriority(Thread.MIN_PRIORITY);
vCapture.start();
}
if (stream.hasAudio()) {
Thread aCapture = new Thread(new Runnable() {
@Override
public void run() {
try {
Socket connection = audioServer.accept();
System.out.println(stream.getName() + " Audio accepted...");
if (stream.hasFakeAudio()) {
fakeAudioIn = new DataInputStream(new BufferedInputStream(connection.getInputStream(), 4096));
}
do {
Tools.sleep(20);
if (fakeVideoIn != null) {
if (fakeVideoIn.available() != 0) {
noAudioPres = false;
Tools.sleep(stream.getADelay());
audioIn = fakeAudioIn;
System.out.println("Start Audio ...");
}
} else if (stream.getName().endsWith(".mp3") || !stream.hasVideo() ) {
noAudioPres = false;
Tools.sleep(stream.getADelay());
audioIn = new DataInputStream(new BufferedInputStream(connection.getInputStream(), 4096));
System.out.println("Start Audio ...");
}
} while (noAudioPres);
} catch (IOException ex) {
Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
aCapture.setPriority(Thread.MIN_PRIORITY);
aCapture.start();
}
}
public void abort() {
try {
if (videoServer != null) {
videoServer.close();
videoServer = null;
videoIn = null;
fakeVideoIn = null;
}
if (audioServer != null) {
audioServer.close();
audioServer = null;
audioIn = null;
fakeAudioIn = null;
}
} catch (IOException ex) {
Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void vPause() {
vPauseFlag = true;
currTime = (int) System.currentTimeMillis();
// System.out.println("VideoCapture Paused ...");
}
public void aPause() {
aPauseFlag = true;
// System.out.println("AudioCapture Paused ...");
}
public void vPlay() {
vPauseFlag = false;
totalPauseTime += pauseTime;
streamTotalEnd = streamEndTime + totalPauseTime;
// System.out.println("VideoCapture Resumed ...");
}
public void aPlay() {
aPauseFlag = false;
// System.out.println("AudioCapture Resumed ...");
}
public int getVideoPort() {
return vport;
}
public int getAudioPort() {
return aport;
}
private WSImage getNextImage() throws IOException {
if (videoIn != null && !vPauseFlag) {
if (stream instanceof SourceMovie || stream instanceof SourceMusic ) {
if (vPauseFlag) {
image.readFully(videoIn);
return image;
} else {
if ((int)System.currentTimeMillis() < streamTotalEnd) {
image.readFully(videoIn);
return image;
} else {
return null;
}
}
} else {
image.readFully(videoIn);
return image;
}
} else {
return null;
}
}
private byte[] getNextAudio() throws IOException {
if (audioIn != null && audioIn.available() > 0 && !aPauseFlag) {
audioIn.readFully(audio);
return audio;
} else {
return null;
}
}
private BufferedImage toCompatibleImage(BufferedImage image) {
GraphicsConfiguration gfx_config = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
if (image.getColorModel().equals(gfx_config.getColorModel())) {
return image;
}
BufferedImage new_image = gfx_config.createCompatibleImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) new_image.getGraphics();
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return new_image;
}
public Frame getFrame() {
BufferedImage nextImage = null;
byte[] nextAudio = null;
try {
if (stream.hasVideo()) {
BufferedImage quantumImage = getNextImage();
if (quantumImage != null) {
nextImage = toCompatibleImage(quantumImage);
} else {
if (stream instanceof SourceMovie || stream instanceof SourceMusic ) {
if (vPauseFlag) {
pauseTime = (int) System.currentTimeMillis() - currTime;
} else {
if ((int)System.currentTimeMillis() > streamTotalEnd && streamEndTime != 0) {
throw new IOException("Time EOS Reached !!!");
}
}
}
}
}
if (stream.hasAudio()) {
nextAudio = getNextAudio();
}
frame.setAudio(nextAudio);
frame.setImage(nextImage);
frame.setOutputFormat(stream.getX(), stream.getY(), stream.getWidth(), stream.getHeight(), stream.getOpacity(), stream.getVolume());
frame.setZOrder(stream.getZOrder());
} catch (IOException ioe) {
stream.stop();
stream.updateStatus();
pauseTime = 0;
totalPauseTime = 0;
// Logger.getLogger(Capturer.class.getName()).log(Level.SEVERE, null, ioe);
}
return frame;
}
static class VideoWrapper extends PushbackInputStream {
VideoWrapper(DataInputStream in) {
super(in);
}
@Override
public int available() throws IOException {
int b = super.read();
// do something specific?
super.unread(b);
return super.available();
}
}
}