You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2014/02/22 10:52:40 UTC
svn commit: r1570813 - in /openmeetings:
branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/
branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/
branches/3.0.x/src/main/java/org/apache/openmeetings/converter/
branches/3.0...
Author: solomax
Date: Sat Feb 22 09:52:39 2014
New Revision: 1570813
URL: http://svn.apache.org/r1570813
Log:
[OPENMEETINGS-902] screen sharing application seems to work as expected
Modified:
openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java
openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java
openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java
openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java
openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java
openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java
openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java
openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java
openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java
openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java
openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java
openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java
openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java
openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java
openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java
openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java
openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java
openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml
Modified: openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java (original)
+++ openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java Sat Feb 22 09:52:39 2014
@@ -85,7 +85,7 @@ public class FlvRecordingMetaDataDao {
public List<FlvRecordingMetaData> getAudioMetaDataByRecording(Long flvRecordingId) {
try {
String hql = "SELECT c FROM FlvRecordingMetaData c WHERE c.flvRecording.flvRecordingId = :flvRecordingId "
- + "AND c.isScreenData = false AND c.streamStatus <> :none "
+ + "AND c.screenData = false AND c.streamStatus <> :none "
+ "AND (c.isAudioOnly = true OR (c.isAudioOnly = false AND c.isVideoOnly = false))";
TypedQuery<FlvRecordingMetaData> query = em.createQuery(hql, FlvRecordingMetaData.class);
@@ -104,7 +104,7 @@ public class FlvRecordingMetaDataDao {
public FlvRecordingMetaData getScreenMetaDataByRecording(Long flvRecordingId) {
try {
String hql = "SELECT c FROM FlvRecordingMetaData c WHERE c.flvRecording.flvRecordingId = :flvRecordingId "
- + "AND c.isScreenData = true";
+ + "AND c.screenData = true";
TypedQuery<FlvRecordingMetaData> query = em.createQuery(hql, FlvRecordingMetaData.class);
query.setParameter("flvRecordingId", flvRecordingId);
@@ -137,7 +137,7 @@ public class FlvRecordingMetaDataDao {
flvRecordingMetaData.setIsAudioOnly(isAudioOnly);
flvRecordingMetaData.setIsVideoOnly(isVideoOnly);
- flvRecordingMetaData.setIsScreenData(isScreenData);
+ flvRecordingMetaData.setScreenData(isScreenData);
flvRecordingMetaData.setStreamName(streamName);
Modified: openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java (original)
+++ openmeetings/branches/3.0.x/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java Sat Feb 22 09:52:39 2014
@@ -95,7 +95,7 @@ public class FlvRecordingMetaData implem
@Column(name = "is_screen_data")
@Element(data = true)
- private Boolean isScreenData;
+ private boolean screenData;
@Column(name = "inserted_by")
@Element(data = true, required = false)
@@ -228,12 +228,12 @@ public class FlvRecordingMetaData implem
this.updated = updated;
}
- public Boolean getIsScreenData() {
- return isScreenData;
+ public boolean isScreenData() {
+ return screenData;
}
- public void setIsScreenData(Boolean isScreenData) {
- this.isScreenData = isScreenData;
+ public void setScreenData(boolean screenData) {
+ this.screenData = screenData;
}
public String getStreamName() {
Modified: openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java (original)
+++ openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java Sat Feb 22 09:52:39 2014
@@ -76,11 +76,6 @@ public class FlvRecorderConverter extend
List<String> listOfFullWaveFiles = new LinkedList<String>();
File streamFolder = getStreamFolder(flvRecording);
try {
- stripAudioFirstPass(flvRecording, returnLog, listOfFullWaveFiles, streamFolder);
-
- // Merge Wave to Full Length
- String streamFolderGeneralName = getStreamsHibernateDir().getCanonicalPath() + File.separator; // FIXME
-
FlvRecordingMetaData screenMetaData = metaDataDao.getScreenMetaDataByRecording(flvRecording.getFlvRecordingId());
if (screenMetaData == null) {
@@ -93,6 +88,11 @@ public class FlvRecorderConverter extend
screenMetaData = waitForTheStream(screenMetaData.getFlvRecordingMetaDataId());
+ stripAudioFirstPass(flvRecording, returnLog, listOfFullWaveFiles, streamFolder);
+
+ // Merge Wave to Full Length
+ String streamFolderGeneralName = getStreamsHibernateDir().getCanonicalPath() + File.separator; // FIXME
+
String hashFileFullName = screenMetaData.getStreamName() + "_FINAL_WAVE.wav";
String outputFullWav = new File(streamFolder, hashFileFullName).getCanonicalPath();
Modified: openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java (original)
+++ openmeetings/branches/3.0.x/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java Sat Feb 22 09:52:39 2014
@@ -287,33 +287,24 @@ public class ScopeApplicationAdapter ext
try {
log.debug("----------- setConnectionAsSharingClient");
IConnection current = Red5.getConnectionLocal();
- // IServiceCapableConnection service = (IServiceCapableConnection)
- // current;
- Client currentClient = this.sessionManager
- .getClientByStreamId(current.getClient().getId(), null);
+ Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
if (currentClient != null) {
+ boolean startRecording = Boolean.valueOf("" + map.get("startRecording"));
+ boolean startStreaming = Boolean.valueOf("" + map.get("startStreaming"));
+ boolean startPublishing = Boolean.valueOf("" + map.get("startPublishing"))
+ && (0 == sessionManager.getPublishingCount(currentClient.getRoom_id()));
- boolean startRecording = Boolean.valueOf("" + map.get(
- "startRecording"));
- boolean startStreaming = Boolean.valueOf("" + map.get(
- "startStreaming"));
- boolean startPublishing = Boolean.valueOf("" + map.get(
- "startPublishing")) && (0 == sessionManager.getPublishingCount(currentClient.getRoom_id()));
-
- currentClient.setRoom_id(Long.parseLong(current.getScope()
- .getName()));
+ currentClient.setRoom_id(Long.parseLong(current.getScope().getName()));
// Set this connection to be a RTMP-Java Client
currentClient.setIsScreenClient(true);
SessionVariablesUtil.setIsScreenClient(current.getClient());
- currentClient.setUser_id(Long.parseLong(map.get("user_id")
- .toString()));
- SessionVariablesUtil.setUserId(current.getClient(), Long.parseLong(map.get("user_id")
- .toString()));
+ currentClient.setUser_id(Long.parseLong(map.get("user_id").toString()));
+ SessionVariablesUtil.setUserId(current.getClient(), Long.parseLong(map.get("user_id").toString()));
boolean alreadyStreaming = currentClient.isStartStreaming();
if (startStreaming) {
@@ -327,11 +318,9 @@ public class ScopeApplicationAdapter ext
currentClient.setStreamPublishStarted(true);
}
- currentClient.setOrganization_id(Long.parseLong(map.get(
- "organization_id").toString()));
+ currentClient.setOrganization_id(Long.parseLong(map.get("organization_id").toString()));
- this.sessionManager.updateClientByStreamId(current
- .getClient().getId(), currentClient, false, null);
+ sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
Map returnMap = new HashMap();
returnMap.put("alreadyPublished", false);
@@ -342,14 +331,10 @@ public class ScopeApplicationAdapter ext
returnMap.put("alreadyPublished", true);
}
- currentClient.setVX(Integer.parseInt(map.get("screenX")
- .toString()));
- currentClient.setVY(Integer.parseInt(map.get("screenY")
- .toString()));
- currentClient.setVWidth(Integer.parseInt(map.get("screenWidth")
- .toString()));
- currentClient.setVHeight(Integer.parseInt(map.get(
- "screenHeight").toString()));
+ currentClient.setVX(Integer.parseInt(map.get("screenX").toString()));
+ currentClient.setVY(Integer.parseInt(map.get("screenY").toString()));
+ currentClient.setVWidth(Integer.parseInt(map.get("screenWidth").toString()));
+ currentClient.setVHeight(Integer.parseInt(map.get("screenHeight").toString()));
log.debug("screen x,y,width,height " + currentClient.getVX()
+ " " + currentClient.getVY() + " "
@@ -358,20 +343,16 @@ public class ScopeApplicationAdapter ext
log.debug("publishName :: " + map.get("publishName"));
- currentClient.setStreamPublishName(map.get("publishName")
- .toString());
+ currentClient.setStreamPublishName(map.get("publishName").toString());
- Client currentScreenUser = this.sessionManager
- .getClientByPublicSID(currentClient
- .getStreamPublishName(), false, null);
+ Client currentScreenUser = sessionManager.getClientByPublicSID(currentClient.getStreamPublishName(), false, null);
currentClient.setFirstname(currentScreenUser.getFirstname());
currentClient.setLastname(currentScreenUser.getLastname());
// This is duplicated, but its not sure that in the meantime
// somebody requests this Client Object Info
- this.sessionManager.updateClientByStreamId(current
- .getClient().getId(), currentClient, false, null);
+ sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
if (startStreaming) {
if (!alreadyStreaming) {
@@ -384,18 +365,19 @@ public class ScopeApplicationAdapter ext
} else {
log.warn("Streaming is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
}
- } else if (startRecording) {
+ }
+ if (startRecording) {
if (!alreadyRecording) {
returnMap.put("modus", "startRecording");
- String recordingName = "Recording "
- + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
+ String recordingName = "Recording " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
flvRecorderService.recordMeetingStream(recordingName, "", false);
} else {
log.warn("Recording is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
}
- } else if (startPublishing) {
+ }
+ if (startPublishing) {
syncMessageToCurrentScope("startedPublishing", new Object[]{currentClient, "rtmp://" + map.get("publishingHost") + ":1935/"
+ map.get("publishingApp") + "/" + map.get("publishingId")}, false, true);
returnMap.put("modus", "startPublishing");
@@ -404,8 +386,7 @@ public class ScopeApplicationAdapter ext
return returnMap;
} else {
- throw new Exception("Could not find Screen Sharing Client "
- + current.getClient().getId());
+ throw new Exception("Could not find Screen Sharing Client " + current.getClient().getId());
}
} catch (Exception err) {
Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java Sat Feb 22 09:52:39 2014
@@ -33,7 +33,6 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import org.apache.mina.core.buffer.IoBuffer;
import org.red5.server.net.rtmp.event.VideoData;
import org.red5.server.stream.message.RTMPMessage;
import org.slf4j.Logger;
@@ -64,7 +63,6 @@ final class CaptureScreen extends Thread
this.host = host;
this.app = app;
this.port = port;
- se = new ScreenV1Encoder(); //NOTE get image should be changed in the code below
}
public void release() {
@@ -87,16 +85,13 @@ final class CaptureScreen extends Thread
}
}
- public void resetBuffer() {
- se.reset();
- }
-
public void run() {
try {
while (active && !core.isReadyToRecord()) {
Thread.sleep(60);
}
timeBetweenFrames = 1000 / FPS;
+ se = new ScreenV1Encoder(3 * FPS); //send keyframe every 3 seconds
scheduler.scheduleWithFixedDelay(new Runnable() {
Robot robot = new Robot();
Rectangle screen = new Rectangle(spinnerX, spinnerY, spinnerWidth, spinnerHeight);
@@ -110,15 +105,12 @@ final class CaptureScreen extends Thread
}
start = System.currentTimeMillis();
try {
- byte[] data = se.encode(screen, image);
+ VideoData data = se.encode(image);
if (log.isTraceEnabled()) {
log.trace(String.format("Image was encoded in %s ms", System.currentTimeMillis() - start));
}
- IoBuffer buf = IoBuffer.allocate(data.length);
- buf.clear();
- buf.put(data);
- buf.flip();
- frames.offer(new VideoData(buf));
+ frames.offer(data);
+ se.createUnalteredFrame(screen);
} catch (IOException e) {
log.error("Error while encoding: ", e);
}
@@ -126,14 +118,15 @@ final class CaptureScreen extends Thread
}, 0, timeBetweenFrames * NANO_MULTIPLIER, TimeUnit.NANOSECONDS);
sendScheduler.scheduleWithFixedDelay(new Runnable() {
public void run() {
- if (frames.size() > 1) {
- frames.poll();
- }
- VideoData f = frames.peek();
+ VideoData f = frames.poll();
+ f = f == null ? se.getUnalteredFrame() : f;
if (f != null) {
try {
timestamp += timeBetweenFrames;
pushVideo(f, (int)timestamp);
+ if (log.isTraceEnabled()) {
+ log.trace("Sending video, timestamp: " + timestamp);
+ }
} catch (IOException e) {
log.error("Error while sending: ", e);
}
Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java Sat Feb 22 09:52:39 2014
@@ -219,20 +219,24 @@ public class CoreScreenShare implements
}
}
- /**
- * @param startStreaming flag denoting the streaming is started
- * @param startRecording flag denoting the recording is started
- */
- public void captureScreenStart(boolean startStreaming, boolean startRecording) {
- captureScreenStart(startStreaming, startRecording, false);
+ public void streamingStart() {
+ startStreaming = true;
+ captureScreenStart();
}
-
- public void captureScreenStart(boolean startStreaming, boolean startRecording, boolean startPublishing) {
+
+ public void recordingStart() {
+ startRecording= true;
+ captureScreenStart();
+ }
+
+ public void publishingStart() {
+ startPublishing = true;
+ captureScreenStart();
+ }
+
+ private void captureScreenStart() {
try {
log.debug("captureScreenStart");
- this.startStreaming = startStreaming;
- this.startRecording= startRecording;
- this.startPublishing = startPublishing;
if (!isConnected) {
instance.connect(host, port, app, this);
@@ -245,13 +249,27 @@ public class CoreScreenShare implements
}
}
- public void sendCaptureScreenStop(boolean stopStreaming, boolean stopRecording) {
+ public void streamingStop() {
+ startStreaming = false;
+ captureScreenStop("stopStreaming");
+ }
+
+ public void recordingStop() {
+ startRecording = false;
+ captureScreenStop("stopRecording");
+ }
+
+ public void publishingStop() {
+ startPublishing = false;
+ captureScreenStop("stopPublishing");
+ }
+
+ private void captureScreenStop(String action) {
try {
log.debug("INVOKE screenSharerAction" );
Map<String, Object> map = new HashMap<String, Object>();
- map.put("stopStreaming", stopStreaming);
- map.put("stopRecording", stopRecording);
+ map.put(action, true);
instance.invoke("screenSharerAction", new Object[] { map }, this);
} catch (Exception err) {
@@ -260,12 +278,6 @@ public class CoreScreenShare implements
}
}
- public void sendStopPublishing() {
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("stopPublishing", true);
- instance.invoke("screenSharerAction", new Object[] { map }, this);
- }
-
public void stopStreaming() {
startStreaming = false;
frame.setSharingStatus(false, !startPublishing && !startRecording && !startStreaming);
@@ -602,7 +614,6 @@ public class CoreScreenShare implements
instance.createStream(this);
} else {
- getCapture().resetBuffer();
log.trace("The Stream was already started ");
}
if (returnMap != null) {
@@ -631,14 +642,10 @@ public class CoreScreenShare implements
if (call.getResult() != null) {
getCapture().setStreamId((Integer)call.getResult());
}
- log.debug("createPublishStream result stream id: " + getCapture().getStreamId());
- log.debug("publishing video by name: " + publishName);
+ log.debug("createPublishStream result stream id: {}; name: {}", getCapture().getStreamId(), publishName);
instance.publish(getCapture().getStreamId(), publishName, "live", this);
- log.debug("setup capture thread");
-
- log.debug("setup capture thread vScreenSpinnerWidth " + spinnerWidth);
- log.debug("setup capture thread vScreenSpinnerHeight " + spinnerHeight);
+ log.debug("setup capture thread spinnerWidth = {}; spinnerHeight = {];", spinnerWidth, spinnerHeight);
getCapture().setSendCursor(true);
getCapture().start();
Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java Sat Feb 22 09:52:39 2014
@@ -21,8 +21,14 @@ package org.apache.openmeetings.screen.w
import java.awt.Rectangle;
import java.io.IOException;
+import org.red5.server.net.rtmp.event.VideoData;
+
public interface IScreenEncoder {
- byte[] encode(Rectangle screen, int[][] img) throws IOException;
+ void createUnalteredFrame(Rectangle area) throws IOException;
+
+ VideoData getUnalteredFrame();
+
+ VideoData encode(int[][] img) throws IOException;
void reset();
}
Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java Sat Feb 22 09:52:39 2014
@@ -67,7 +67,7 @@ class RTMPClientPublish extends RTMPClie
private void connectionClosed() {
publishScreen.setStartPublish(false);
publishScreen.release();
- core.sendStopPublishing();
+ core.publishingStop();
}
@Override
Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java Sat Feb 22 09:52:39 2014
@@ -32,6 +32,9 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.Deflater;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.red5.server.net.rtmp.event.VideoData;
+
public class ScreenV1Encoder extends BaseScreenEncoder {
private int[][] last = null;
private static int KEY_FRAME_INDEX = 25;
@@ -41,16 +44,20 @@ public class ScreenV1Encoder extends Bas
private int keyFrameIndex;
private int frameCount = 0;
private int blockSize;
- private Rectangle screen;
private ByteArrayOutputStream ba = new ByteArrayOutputStream(50 + 3 * DEFAULT_SCREEN_WIDTH * DEFAULT_SCREEN_HEIGHT);
private byte[] areaBuf = null;
private Deflater d = new Deflater(Deflater.DEFAULT_COMPRESSION);
private byte[] zipBuf = null;
+ private VideoData unalteredFrame = null;
public ScreenV1Encoder() {
this(KEY_FRAME_INDEX, DEFAULT_BLOCK_SIZE);
}
+ public ScreenV1Encoder(int keyFrameIndex) {
+ this(keyFrameIndex, DEFAULT_BLOCK_SIZE);
+ }
+
//will create square blocks
public ScreenV1Encoder(int keyFrameIndex, int blockSize) {
this.keyFrameIndex = keyFrameIndex;
@@ -62,12 +69,47 @@ public class ScreenV1Encoder extends Bas
areaBuf = new byte[3 * blockSize * blockSize];
zipBuf = new byte[3 * blockSize * blockSize];
}
+
+ private VideoData getData(byte[] data) {
+ IoBuffer buf = IoBuffer.allocate(data.length);
+ buf.clear();
+ buf.put(data);
+ buf.flip();
+ return new VideoData(buf);
+ }
+
+ public void createUnalteredFrame(Rectangle _area) throws IOException {
+ if (last == null) {
+ return;
+ }
+ if (unalteredFrame == null) {
+ ByteArrayOutputStream ba = new ByteArrayOutputStream(200);
+
+ //header
+ ba.write(getTag(FLAG_FRAMETYPE_INTERFRAME, FLAG_CODEC_SCREEN));
+ writeShort(ba, _area.width + ((blockSize / 16 - 1) << 12));
+ writeShort(ba, _area.height + ((blockSize / 16 - 1) << 12));
+ Rectangle area = getNextBlock(_area, null);
+ while (area.width > 0 && area.height > 0) {
+ writeShort(ba, 0);
+ area = getNextBlock(_area, area);
+ }
+ unalteredFrame = getData(ba.toByteArray());
+ }
+ }
+
+ public VideoData getUnalteredFrame() {
+ if (unalteredFrame != null && (frameCount % keyFrameIndex) != 0) {
+ frameCount++;
+ }
+ return unalteredFrame;
+ }
- public synchronized byte[] encode(Rectangle screen, int[][] img) throws IOException {
+ public synchronized VideoData encode(int[][] img) throws IOException {
ba.reset();
Rectangle imgArea = new Rectangle(img.length, img[0].length);
Rectangle area = getNextBlock(imgArea, null);
- boolean isKeyFrame = (frameCount++ % keyFrameIndex) == 0 || last == null || !screen.equals(this.screen);
+ boolean isKeyFrame = (frameCount++ % keyFrameIndex) == 0 || last == null;
//header
ba.write(getTag(isKeyFrame ? FLAG_FRAMETYPE_KEYFRAME : FLAG_FRAMETYPE_INTERFRAME, FLAG_CODEC_SCREEN));
@@ -78,13 +120,13 @@ public class ScreenV1Encoder extends Bas
writeBytesIfChanged(ba, isKeyFrame, img, area);
area = getNextBlock(imgArea, area);
}
- this.screen = screen;
last = img;
- return ba.toByteArray();
+ return getData(ba.toByteArray());
}
public void reset() {
last = null;
+ unalteredFrame = null;
}
private Rectangle getNextBlock(Rectangle img, Rectangle _prev) {
Modified: openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java
URL: http://svn.apache.org/viewvc/openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java (original)
+++ openmeetings/branches/3.0.x/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java Sat Feb 22 09:52:39 2014
@@ -266,14 +266,14 @@ public class ScreenSharerFrame extends J
if (sharingStarted) {
if (!sharingActionRequested) {
sharingActionRequested = true;
- core.sendCaptureScreenStop(true, false);
+ core.streamingStop();;
} else {
logger.warn("Sharing action is already requested");
}
} else {
if (!sharingActionRequested) {
sharingActionRequested = true;
- core.captureScreenStart(true, false);
+ core.streamingStart();
} else {
logger.warn("Sharing action is already requested");
}
@@ -490,14 +490,14 @@ public class ScreenSharerFrame extends J
if (recordingStarted) {
if (!recordingActionRequested) {
recordingActionRequested = true;
- core.sendCaptureScreenStop(false, true);
+ core.recordingStop();
} else {
logger.warn("Recording action is already requested");
}
} else {
if (!recordingActionRequested) {
recordingActionRequested = true;
- core.captureScreenStart(false, true);
+ core.recordingStart();
} else {
logger.warn("Recording action is already requested");
}
@@ -557,14 +557,14 @@ public class ScreenSharerFrame extends J
if (publishStarted) {
if (!publishingActionRequested) {
publishingActionRequested = true;
- core.sendStopPublishing();
+ core.publishingStop();
} else {
logger.warn("Publishing action is already requested");
}
} else {
if (!publishingActionRequested) {
publishingActionRequested = true;
- core.captureScreenStart(false, false, true);
+ core.publishingStart();
} else {
logger.warn("Publishing action is already requested");
}
Modified: openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java (original)
+++ openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/dao/record/FlvRecordingMetaDataDao.java Sat Feb 22 09:52:39 2014
@@ -85,7 +85,7 @@ public class FlvRecordingMetaDataDao {
public List<FlvRecordingMetaData> getAudioMetaDataByRecording(Long flvRecordingId) {
try {
String hql = "SELECT c FROM FlvRecordingMetaData c WHERE c.flvRecording.flvRecordingId = :flvRecordingId "
- + "AND c.isScreenData = false AND c.streamStatus <> :none "
+ + "AND c.screenData = false AND c.streamStatus <> :none "
+ "AND (c.isAudioOnly = true OR (c.isAudioOnly = false AND c.isVideoOnly = false))";
TypedQuery<FlvRecordingMetaData> query = em.createQuery(hql, FlvRecordingMetaData.class);
@@ -104,7 +104,7 @@ public class FlvRecordingMetaDataDao {
public FlvRecordingMetaData getScreenMetaDataByRecording(Long flvRecordingId) {
try {
String hql = "SELECT c FROM FlvRecordingMetaData c WHERE c.flvRecording.flvRecordingId = :flvRecordingId "
- + "AND c.isScreenData = true";
+ + "AND c.screenData = true";
TypedQuery<FlvRecordingMetaData> query = em.createQuery(hql, FlvRecordingMetaData.class);
query.setParameter("flvRecordingId", flvRecordingId);
@@ -137,7 +137,7 @@ public class FlvRecordingMetaDataDao {
flvRecordingMetaData.setIsAudioOnly(isAudioOnly);
flvRecordingMetaData.setIsVideoOnly(isVideoOnly);
- flvRecordingMetaData.setIsScreenData(isScreenData);
+ flvRecordingMetaData.setScreenData(isScreenData);
flvRecordingMetaData.setStreamName(streamName);
Modified: openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java (original)
+++ openmeetings/trunk/singlewebapp/src/db/java/org/apache/openmeetings/db/entity/record/FlvRecordingMetaData.java Sat Feb 22 09:52:39 2014
@@ -95,7 +95,7 @@ public class FlvRecordingMetaData implem
@Column(name = "is_screen_data")
@Element(data = true)
- private Boolean isScreenData;
+ private boolean screenData;
@Column(name = "inserted_by")
@Element(data = true, required = false)
@@ -228,12 +228,12 @@ public class FlvRecordingMetaData implem
this.updated = updated;
}
- public Boolean getIsScreenData() {
- return isScreenData;
+ public boolean isScreenData() {
+ return screenData;
}
- public void setIsScreenData(Boolean isScreenData) {
- this.isScreenData = isScreenData;
+ public void setScreenData(boolean screenData) {
+ this.screenData = screenData;
}
public String getStreamName() {
Modified: openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java (original)
+++ openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/converter/FlvRecorderConverter.java Sat Feb 22 09:52:39 2014
@@ -76,11 +76,6 @@ public class FlvRecorderConverter extend
List<String> listOfFullWaveFiles = new LinkedList<String>();
File streamFolder = getStreamFolder(flvRecording);
try {
- stripAudioFirstPass(flvRecording, returnLog, listOfFullWaveFiles, streamFolder);
-
- // Merge Wave to Full Length
- String streamFolderGeneralName = getStreamsHibernateDir().getCanonicalPath() + File.separator; // FIXME
-
FlvRecordingMetaData screenMetaData = metaDataDao.getScreenMetaDataByRecording(flvRecording.getFlvRecordingId());
if (screenMetaData == null) {
@@ -93,6 +88,11 @@ public class FlvRecorderConverter extend
screenMetaData = waitForTheStream(screenMetaData.getFlvRecordingMetaDataId());
+ stripAudioFirstPass(flvRecording, returnLog, listOfFullWaveFiles, streamFolder);
+
+ // Merge Wave to Full Length
+ String streamFolderGeneralName = getStreamsHibernateDir().getCanonicalPath() + File.separator; // FIXME
+
String hashFileFullName = screenMetaData.getStreamName() + "_FINAL_WAVE.wav";
String outputFullWav = new File(streamFolder, hashFileFullName).getCanonicalPath();
Modified: openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java (original)
+++ openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/data/flvrecord/listener/async/BaseStreamWriter.java Sat Feb 22 09:52:39 2014
@@ -32,12 +32,12 @@ import org.apache.openmeetings.db.entity
import org.apache.openmeetings.db.entity.record.FlvRecordingMetaData.Status;
import org.apache.openmeetings.util.OmFileHelper;
import org.red5.io.IStreamableFile;
+import org.red5.io.IStreamableFileFactory;
+import org.red5.io.IStreamableFileService;
import org.red5.io.ITagWriter;
+import org.red5.io.StreamableFileFactory;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.scope.IScope;
-import org.red5.server.api.service.IStreamableFileService;
-import org.red5.server.api.stream.IStreamableFileFactory;
-import org.red5.server.stream.StreamableFileFactory;
import org.red5.server.util.ScopeUtils;
import org.slf4j.Logger;
Modified: openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java (original)
+++ openmeetings/trunk/singlewebapp/src/main/java/org/apache/openmeetings/remote/red5/ScopeApplicationAdapter.java Sat Feb 22 09:52:39 2014
@@ -287,33 +287,24 @@ public class ScopeApplicationAdapter ext
try {
log.debug("----------- setConnectionAsSharingClient");
IConnection current = Red5.getConnectionLocal();
- // IServiceCapableConnection service = (IServiceCapableConnection)
- // current;
- Client currentClient = this.sessionManager
- .getClientByStreamId(current.getClient().getId(), null);
+ Client currentClient = sessionManager.getClientByStreamId(current.getClient().getId(), null);
if (currentClient != null) {
+ boolean startRecording = Boolean.valueOf("" + map.get("startRecording"));
+ boolean startStreaming = Boolean.valueOf("" + map.get("startStreaming"));
+ boolean startPublishing = Boolean.valueOf("" + map.get("startPublishing"))
+ && (0 == sessionManager.getPublishingCount(currentClient.getRoom_id()));
- boolean startRecording = Boolean.valueOf("" + map.get(
- "startRecording"));
- boolean startStreaming = Boolean.valueOf("" + map.get(
- "startStreaming"));
- boolean startPublishing = Boolean.valueOf("" + map.get(
- "startPublishing")) && (0 == sessionManager.getPublishingCount(currentClient.getRoom_id()));
-
- currentClient.setRoom_id(Long.parseLong(current.getScope()
- .getName()));
+ currentClient.setRoom_id(Long.parseLong(current.getScope().getName()));
// Set this connection to be a RTMP-Java Client
currentClient.setIsScreenClient(true);
SessionVariablesUtil.setIsScreenClient(current.getClient());
- currentClient.setUser_id(Long.parseLong(map.get("user_id")
- .toString()));
- SessionVariablesUtil.setUserId(current.getClient(), Long.parseLong(map.get("user_id")
- .toString()));
+ currentClient.setUser_id(Long.parseLong(map.get("user_id").toString()));
+ SessionVariablesUtil.setUserId(current.getClient(), Long.parseLong(map.get("user_id").toString()));
boolean alreadyStreaming = currentClient.isStartStreaming();
if (startStreaming) {
@@ -327,11 +318,9 @@ public class ScopeApplicationAdapter ext
currentClient.setStreamPublishStarted(true);
}
- currentClient.setOrganization_id(Long.parseLong(map.get(
- "organization_id").toString()));
+ currentClient.setOrganization_id(Long.parseLong(map.get("organization_id").toString()));
- this.sessionManager.updateClientByStreamId(current
- .getClient().getId(), currentClient, false, null);
+ sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
Map returnMap = new HashMap();
returnMap.put("alreadyPublished", false);
@@ -342,14 +331,10 @@ public class ScopeApplicationAdapter ext
returnMap.put("alreadyPublished", true);
}
- currentClient.setVX(Integer.parseInt(map.get("screenX")
- .toString()));
- currentClient.setVY(Integer.parseInt(map.get("screenY")
- .toString()));
- currentClient.setVWidth(Integer.parseInt(map.get("screenWidth")
- .toString()));
- currentClient.setVHeight(Integer.parseInt(map.get(
- "screenHeight").toString()));
+ currentClient.setVX(Integer.parseInt(map.get("screenX").toString()));
+ currentClient.setVY(Integer.parseInt(map.get("screenY").toString()));
+ currentClient.setVWidth(Integer.parseInt(map.get("screenWidth").toString()));
+ currentClient.setVHeight(Integer.parseInt(map.get("screenHeight").toString()));
log.debug("screen x,y,width,height " + currentClient.getVX()
+ " " + currentClient.getVY() + " "
@@ -358,20 +343,16 @@ public class ScopeApplicationAdapter ext
log.debug("publishName :: " + map.get("publishName"));
- currentClient.setStreamPublishName(map.get("publishName")
- .toString());
+ currentClient.setStreamPublishName(map.get("publishName").toString());
- Client currentScreenUser = this.sessionManager
- .getClientByPublicSID(currentClient
- .getStreamPublishName(), false, null);
+ Client currentScreenUser = sessionManager.getClientByPublicSID(currentClient.getStreamPublishName(), false, null);
currentClient.setFirstname(currentScreenUser.getFirstname());
currentClient.setLastname(currentScreenUser.getLastname());
// This is duplicated, but its not sure that in the meantime
// somebody requests this Client Object Info
- this.sessionManager.updateClientByStreamId(current
- .getClient().getId(), currentClient, false, null);
+ sessionManager.updateClientByStreamId(current.getClient().getId(), currentClient, false, null);
if (startStreaming) {
if (!alreadyStreaming) {
@@ -384,18 +365,19 @@ public class ScopeApplicationAdapter ext
} else {
log.warn("Streaming is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
}
- } else if (startRecording) {
+ }
+ if (startRecording) {
if (!alreadyRecording) {
returnMap.put("modus", "startRecording");
- String recordingName = "Recording "
- + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
+ String recordingName = "Recording " + CalendarPatterns.getDateWithTimeByMiliSeconds(new Date());
flvRecorderService.recordMeetingStream(recordingName, "", false);
} else {
log.warn("Recording is already started for the client id=" + currentClient.getId() + ". Second request is ignored.");
}
- } else if (startPublishing) {
+ }
+ if (startPublishing) {
syncMessageToCurrentScope("startedPublishing", new Object[]{currentClient, "rtmp://" + map.get("publishingHost") + ":1935/"
+ map.get("publishingApp") + "/" + map.get("publishingId")}, false, true);
returnMap.put("modus", "startPublishing");
@@ -404,8 +386,7 @@ public class ScopeApplicationAdapter ext
return returnMap;
} else {
- throw new Exception("Could not find Screen Sharing Client "
- + current.getClient().getId());
+ throw new Exception("Could not find Screen Sharing Client " + current.getClient().getId());
}
} catch (Exception err) {
Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CaptureScreen.java Sat Feb 22 09:52:39 2014
@@ -28,11 +28,11 @@ import static org.slf4j.LoggerFactory.ge
import java.awt.Rectangle;
import java.awt.Robot;
import java.io.IOException;
+import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import org.apache.mina.core.buffer.IoBuffer;
import org.red5.server.net.rtmp.event.VideoData;
import org.red5.server.stream.message.RTMPMessage;
import org.slf4j.Logger;
@@ -46,13 +46,14 @@ final class CaptureScreen extends Thread
private volatile boolean active = true;
private IScreenEncoder se;
private IScreenShare client;
- private IoBuffer buffer;
+ private ArrayBlockingQueue<VideoData> frames = new ArrayBlockingQueue<VideoData>(2);
private String host = null;
private String app = null;
private int port = -1;
private int streamId;
private boolean startPublish = false;
private boolean sendCursor = false;
+ private final ScheduledExecutorService sendScheduler = Executors.newScheduledThreadPool(1);
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(20);
private final ScheduledExecutorService cursorScheduler = Executors.newScheduledThreadPool(1);
@@ -62,7 +63,6 @@ final class CaptureScreen extends Thread
this.host = host;
this.app = app;
this.port = port;
- se = new ScreenV1Encoder(); //NOTE get image should be changed in the code below
}
public void release() {
@@ -74,22 +74,24 @@ final class CaptureScreen extends Thread
//no-op
}
try {
+ sendScheduler.shutdownNow();
+ } catch (Exception e) {
+ //no-op
+ }
+ try {
cursorScheduler.shutdownNow();
} catch (Exception e) {
//no-op
}
}
- public void resetBuffer() {
- se.reset();
- }
-
public void run() {
try {
while (active && !core.isReadyToRecord()) {
Thread.sleep(60);
}
timeBetweenFrames = 1000 / FPS;
+ se = new ScreenV1Encoder(3 * FPS); //send keyframe every 3 seconds
scheduler.scheduleWithFixedDelay(new Runnable() {
Robot robot = new Robot();
Rectangle screen = new Rectangle(spinnerX, spinnerY, spinnerWidth, spinnerHeight);
@@ -103,14 +105,31 @@ final class CaptureScreen extends Thread
}
start = System.currentTimeMillis();
try {
- byte[] data = se.encode(screen, image);
+ VideoData data = se.encode(image);
if (log.isTraceEnabled()) {
log.trace(String.format("Image was encoded in %s ms", System.currentTimeMillis() - start));
}
- timestamp += timeBetweenFrames;
- pushVideo(data, timestamp);
+ frames.offer(data);
+ se.createUnalteredFrame(screen);
} catch (IOException e) {
- log.error("Error while encoding/sending: ", e);
+ log.error("Error while encoding: ", e);
+ }
+ }
+ }, 0, timeBetweenFrames * NANO_MULTIPLIER, TimeUnit.NANOSECONDS);
+ sendScheduler.scheduleWithFixedDelay(new Runnable() {
+ public void run() {
+ VideoData f = frames.poll();
+ f = f == null ? se.getUnalteredFrame() : f;
+ if (f != null) {
+ try {
+ timestamp += timeBetweenFrames;
+ pushVideo(f, (int)timestamp);
+ if (log.isTraceEnabled()) {
+ log.trace("Sending video, timestamp: " + timestamp);
+ }
+ } catch (IOException e) {
+ log.error("Error while sending: ", e);
+ }
}
}
}, 0, timeBetweenFrames * NANO_MULTIPLIER, TimeUnit.NANOSECONDS);
@@ -143,19 +162,9 @@ final class CaptureScreen extends Thread
}
*/
- private void pushVideo(byte[] video, int ts) throws IOException {
+ private void pushVideo(VideoData data, int ts) throws IOException {
if (startPublish) {
- if (buffer == null || (buffer.capacity() < video.length && !buffer.isAutoExpand())) {
- buffer = IoBuffer.allocate(video.length);
- buffer.setAutoExpand(true);
- }
-
- buffer.clear();
- buffer.put(video);
- buffer.flip();
-
- log.trace("Video frame sent :: " + ts);
- RTMPMessage rtmpMsg = RTMPMessage.build(new VideoData(buffer), ts);
+ RTMPMessage rtmpMsg = RTMPMessage.build(data, ts);
client.publishStreamData(streamId, rtmpMsg);
}
}
Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/CoreScreenShare.java Sat Feb 22 09:52:39 2014
@@ -214,26 +214,29 @@ public class CoreScreenShare implements
instance.invoke("setConnectionAsSharingClient", new Object[] { map }, this);
} catch (Exception err) {
- log.error("setConnectionAsSharingClient Exception: ", err);
frame.setStatus("Error: " + err.getLocalizedMessage());
log.error("[setConnectionAsSharingClient]", err);
}
}
- /**
- * @param startStreaming flag denoting the streaming is started
- * @param startRecording flag denoting the recording is started
- */
- public void captureScreenStart(boolean startStreaming, boolean startRecording) {
- captureScreenStart(startStreaming, startRecording, false);
+ public void streamingStart() {
+ startStreaming = true;
+ captureScreenStart();
}
-
- public void captureScreenStart(boolean startStreaming, boolean startRecording, boolean startPublishing) {
+
+ public void recordingStart() {
+ startRecording= true;
+ captureScreenStart();
+ }
+
+ public void publishingStart() {
+ startPublishing = true;
+ captureScreenStart();
+ }
+
+ private void captureScreenStart() {
try {
log.debug("captureScreenStart");
- this.startStreaming = startStreaming;
- this.startRecording= startRecording;
- this.startPublishing = startPublishing;
if (!isConnected) {
instance.connect(host, port, app, this);
@@ -246,13 +249,27 @@ public class CoreScreenShare implements
}
}
- public void sendCaptureScreenStop(boolean stopStreaming, boolean stopRecording) {
+ public void streamingStop() {
+ startStreaming = false;
+ captureScreenStop("stopStreaming");
+ }
+
+ public void recordingStop() {
+ startRecording = false;
+ captureScreenStop("stopRecording");
+ }
+
+ public void publishingStop() {
+ startPublishing = false;
+ captureScreenStop("stopPublishing");
+ }
+
+ private void captureScreenStop(String action) {
try {
log.debug("INVOKE screenSharerAction" );
Map<String, Object> map = new HashMap<String, Object>();
- map.put("stopStreaming", stopStreaming);
- map.put("stopRecording", stopRecording);
+ map.put(action, true);
instance.invoke("screenSharerAction", new Object[] { map }, this);
} catch (Exception err) {
@@ -261,12 +278,6 @@ public class CoreScreenShare implements
}
}
- public void sendStopPublishing() {
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("stopPublishing", true);
- instance.invoke("screenSharerAction", new Object[] { map }, this);
- }
-
public void stopStreaming() {
startStreaming = false;
frame.setSharingStatus(false, !startPublishing && !startRecording && !startStreaming);
@@ -603,7 +614,6 @@ public class CoreScreenShare implements
instance.createStream(this);
} else {
- getCapture().resetBuffer();
log.trace("The Stream was already started ");
}
if (returnMap != null) {
@@ -632,14 +642,10 @@ public class CoreScreenShare implements
if (call.getResult() != null) {
getCapture().setStreamId((Integer)call.getResult());
}
- log.debug("createPublishStream result stream id: " + getCapture().getStreamId());
- log.debug("publishing video by name: " + publishName);
+ log.debug("createPublishStream result stream id: {}; name: {}", getCapture().getStreamId(), publishName);
instance.publish(getCapture().getStreamId(), publishName, "live", this);
- log.debug("setup capture thread");
-
- log.debug("setup capture thread vScreenSpinnerWidth " + spinnerWidth);
- log.debug("setup capture thread vScreenSpinnerHeight " + spinnerHeight);
+ log.debug("setup capture thread spinnerWidth = {}; spinnerHeight = {];", spinnerWidth, spinnerHeight);
getCapture().setSendCursor(true);
getCapture().start();
Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/IScreenEncoder.java Sat Feb 22 09:52:39 2014
@@ -21,8 +21,14 @@ package org.apache.openmeetings.screen.w
import java.awt.Rectangle;
import java.io.IOException;
+import org.red5.server.net.rtmp.event.VideoData;
+
public interface IScreenEncoder {
- byte[] encode(Rectangle screen, int[][] img) throws IOException;
+ void createUnalteredFrame(Rectangle area) throws IOException;
+
+ VideoData getUnalteredFrame();
+
+ VideoData encode(int[][] img) throws IOException;
void reset();
}
Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/RTMPClientPublish.java Sat Feb 22 09:52:39 2014
@@ -67,7 +67,7 @@ class RTMPClientPublish extends RTMPClie
private void connectionClosed() {
publishScreen.setStartPublish(false);
publishScreen.release();
- core.sendStopPublishing();
+ core.publishingStop();
}
@Override
Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/ScreenV1Encoder.java Sat Feb 22 09:52:39 2014
@@ -32,6 +32,9 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.Deflater;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.red5.server.net.rtmp.event.VideoData;
+
public class ScreenV1Encoder extends BaseScreenEncoder {
private int[][] last = null;
private static int KEY_FRAME_INDEX = 25;
@@ -41,16 +44,20 @@ public class ScreenV1Encoder extends Bas
private int keyFrameIndex;
private int frameCount = 0;
private int blockSize;
- private Rectangle screen;
private ByteArrayOutputStream ba = new ByteArrayOutputStream(50 + 3 * DEFAULT_SCREEN_WIDTH * DEFAULT_SCREEN_HEIGHT);
private byte[] areaBuf = null;
private Deflater d = new Deflater(Deflater.DEFAULT_COMPRESSION);
private byte[] zipBuf = null;
+ private VideoData unalteredFrame = null;
public ScreenV1Encoder() {
this(KEY_FRAME_INDEX, DEFAULT_BLOCK_SIZE);
}
+ public ScreenV1Encoder(int keyFrameIndex) {
+ this(keyFrameIndex, DEFAULT_BLOCK_SIZE);
+ }
+
//will create square blocks
public ScreenV1Encoder(int keyFrameIndex, int blockSize) {
this.keyFrameIndex = keyFrameIndex;
@@ -62,12 +69,47 @@ public class ScreenV1Encoder extends Bas
areaBuf = new byte[3 * blockSize * blockSize];
zipBuf = new byte[3 * blockSize * blockSize];
}
+
+ private VideoData getData(byte[] data) {
+ IoBuffer buf = IoBuffer.allocate(data.length);
+ buf.clear();
+ buf.put(data);
+ buf.flip();
+ return new VideoData(buf);
+ }
+
+ public void createUnalteredFrame(Rectangle _area) throws IOException {
+ if (last == null) {
+ return;
+ }
+ if (unalteredFrame == null) {
+ ByteArrayOutputStream ba = new ByteArrayOutputStream(200);
+
+ //header
+ ba.write(getTag(FLAG_FRAMETYPE_INTERFRAME, FLAG_CODEC_SCREEN));
+ writeShort(ba, _area.width + ((blockSize / 16 - 1) << 12));
+ writeShort(ba, _area.height + ((blockSize / 16 - 1) << 12));
+ Rectangle area = getNextBlock(_area, null);
+ while (area.width > 0 && area.height > 0) {
+ writeShort(ba, 0);
+ area = getNextBlock(_area, area);
+ }
+ unalteredFrame = getData(ba.toByteArray());
+ }
+ }
+
+ public VideoData getUnalteredFrame() {
+ if (unalteredFrame != null && (frameCount % keyFrameIndex) != 0) {
+ frameCount++;
+ }
+ return unalteredFrame;
+ }
- public synchronized byte[] encode(Rectangle screen, int[][] img) throws IOException {
+ public synchronized VideoData encode(int[][] img) throws IOException {
ba.reset();
Rectangle imgArea = new Rectangle(img.length, img[0].length);
Rectangle area = getNextBlock(imgArea, null);
- boolean isKeyFrame = (frameCount++ % keyFrameIndex) == 0 || last == null || !screen.equals(this.screen);
+ boolean isKeyFrame = (frameCount++ % keyFrameIndex) == 0 || last == null;
//header
ba.write(getTag(isKeyFrame ? FLAG_FRAMETYPE_KEYFRAME : FLAG_FRAMETYPE_INTERFRAME, FLAG_CODEC_SCREEN));
@@ -78,13 +120,13 @@ public class ScreenV1Encoder extends Bas
writeBytesIfChanged(ba, isKeyFrame, img, area);
area = getNextBlock(imgArea, area);
}
- this.screen = screen;
last = img;
- return ba.toByteArray();
+ return getData(ba.toByteArray());
}
public void reset() {
last = null;
+ unalteredFrame = null;
}
private Rectangle getNextBlock(Rectangle img, Rectangle _prev) {
Modified: openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/java/org/apache/openmeetings/screen/webstart/gui/ScreenSharerFrame.java Sat Feb 22 09:52:39 2014
@@ -266,14 +266,14 @@ public class ScreenSharerFrame extends J
if (sharingStarted) {
if (!sharingActionRequested) {
sharingActionRequested = true;
- core.sendCaptureScreenStop(true, false);
+ core.streamingStop();;
} else {
logger.warn("Sharing action is already requested");
}
} else {
if (!sharingActionRequested) {
sharingActionRequested = true;
- core.captureScreenStart(true, false);
+ core.streamingStart();
} else {
logger.warn("Sharing action is already requested");
}
@@ -466,7 +466,7 @@ public class ScreenSharerFrame extends J
calcRescaleFactors();
}
});
- comboFPS.setSelectedIndex(1);
+ comboFPS.setSelectedIndex(2);
comboFPS.setBounds(390, 170, 70, 24);
panelScreen.add(comboFPS);
@@ -490,14 +490,14 @@ public class ScreenSharerFrame extends J
if (recordingStarted) {
if (!recordingActionRequested) {
recordingActionRequested = true;
- core.sendCaptureScreenStop(false, true);
+ core.recordingStop();
} else {
logger.warn("Recording action is already requested");
}
} else {
if (!recordingActionRequested) {
recordingActionRequested = true;
- core.captureScreenStart(false, true);
+ core.recordingStart();
} else {
logger.warn("Recording action is already requested");
}
@@ -557,14 +557,14 @@ public class ScreenSharerFrame extends J
if (publishStarted) {
if (!publishingActionRequested) {
publishingActionRequested = true;
- core.sendStopPublishing();
+ core.publishingStop();
} else {
logger.warn("Publishing action is already requested");
}
} else {
if (!publishingActionRequested) {
publishingActionRequested = true;
- core.captureScreenStart(false, false, true);
+ core.publishingStart();
} else {
logger.warn("Publishing action is already requested");
}
Modified: openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml
URL: http://svn.apache.org/viewvc/openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml?rev=1570813&r1=1570812&r2=1570813&view=diff
==============================================================================
--- openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml (original)
+++ openmeetings/trunk/singlewebapp/src/screenshare/resources/logback.xml Sat Feb 22 09:52:39 2014
@@ -19,35 +19,33 @@
-->
-<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="logback.xsd">
+<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="logback.xsd">
<contextName>${current_openmeetings_context_name}</contextName>
-
+
<jmxConfigurator contextName="${current_openmeetings_context_name}" />
- <appender name="FLOG2" class="ch.qos.logback.core.FileAppender">
+ <appender name="FLOG2" class="ch.qos.logback.core.FileAppender">
<File>screensharing.log</File>
<Append>false</Append>
<Encoding>UTF-8</Encoding>
<BufferedIO>false</BufferedIO>
<ImmediateFlush>true</ImmediateFlush>
<layout class="ch.qos.logback.classic.PatternLayout">
- <Pattern>
- %5p %d{MM-dd HH:mm:ss.SSS } %F %r %L %c [%t] - %m%n
- </Pattern>
+ <pattern>%5p %d{MM-dd HH:mm:ss.SSS } %L %c{10} [%t] - %m%n</pattern>
+ </layout>
+ </appender>
+ <appender name="CONSOLE2" class="ch.qos.logback.core.ConsoleAppender">
+ <layout class="ch.qos.logback.classic.PatternLayout">
+ <pattern>%5p %d{MM-dd HH:mm:ss.SSS } %L %c{10} [%t] - %m%n</pattern>
</layout>
- </appender>
- <appender name="CONSOLE2" class="ch.qos.logback.core.ConsoleAppender">
- <layout class="ch.qos.logback.classic.PatternLayout">
- <pattern>%5p %d{MM-dd HH:mm:ss.SSS } %F %r %L %c [%t] - %m%n</pattern>
- </layout>
- </appender>
- <logger name="org.apache.openmeetings">
- <level value="TRACE"/>
- </logger>
- <root>
- <level value="TRACE"/>
- <appender-ref ref="FLOG2"/>
- <appender-ref ref="CONSOLE2"/>
- </root>
+ </appender>
+ <logger name="org.apache.openmeetings">
+ <level value="DEBUG" />
+ </logger>
+ <root>
+ <level value="DEBUG" />
+ <appender-ref ref="FLOG2" />
+ <appender-ref ref="CONSOLE2" />
+ </root>
</configuration>