/*
* (C) Copyright 2014 Kurento (http://kurento.org/)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
package com.kurento.demo.cpbrazil;
import static com.google.common.collect.Lists.newArrayList;
import java.net.URISyntaxException;
import java.util.Calendar;
import org.springframework.beans.factory.annotation.Autowired;
import com.kurento.demo.cpbrazil.CpbWindows.Windows;
import com.kurento.demo.cpbrazil.youtube.Videos;
import com.kurento.kmf.content.ContentCommand;
import com.kurento.kmf.content.ContentCommandResult;
import com.kurento.kmf.content.WebRtcContentHandler;
import com.kurento.kmf.content.WebRtcContentService;
import com.kurento.kmf.content.WebRtcContentSession;
import com.kurento.kmf.media.ChromaFilter;
import com.kurento.kmf.media.FaceOverlayFilter;
import com.kurento.kmf.media.GStreamerFilter;
import com.kurento.kmf.media.MediaApiConfiguration;
import com.kurento.kmf.media.MediaPipeline;
import com.kurento.kmf.media.PointerDetectorAdvFilter;
import com.kurento.kmf.media.PointerDetectorWindowMediaParam;
import com.kurento.kmf.media.RecorderEndpoint;
import com.kurento.kmf.media.WebRtcEndpoint;
import com.kurento.kmf.media.WindowParam;
import com.kurento.kmf.media.events.MediaEventListener;
import com.kurento.kmf.media.events.WindowInEvent;
import com.kurento.kmf.repository.RepositoryHttpRecorder;
import com.kurento.kmf.repository.RepositoryItem;
/**
* Campus Party Brazil 2014 Kurento demo. This demo has the following pipeline:
*
* WebRTC -> RateLimiter -> MirrorFilter -> PointerDetectorFilter ->
* ChromaFilter -> FaceOverlayFilter -> Recorder
*
* @author Boni GarcĂa (bgarcia@gsyc.es)
* @since 1.0.1
*/
@WebRtcContentService(path = "/cpbWebRtc/*")
public class CpbWebRtc extends WebRtcContentHandler {
// MediaPipeline and MediaElements
public MediaPipeline mediaPipeline;
public GStreamerFilter mirrorFilter;
public GStreamerFilter rateLimiter;
public PointerDetectorAdvFilter pointerDetectorAdvFilter;
public FaceOverlayFilter faceOverlayFilter;
public ChromaFilter chromaFilter;
public RecorderEndpoint recorderEndpoint;
// Token to upload videos to Kurento Brazil Demo playlist
private static final String PLAYLIST_TOKEN = "PL58tWS2XjtialwG-eWDYoFwQpHTd5vDEE";
// Global demo elements
public CpbWindows cpbWindows;
public String itemId;
public Windows activeWindow;
private String handlerUrl;
private String recorderUrl;
private int mario = 1;
private int count = 1;
@Autowired
private MediaApiConfiguration config;
@Override
public void onContentRequest(final WebRtcContentSession contentSession)
throws Exception {
String contentId = contentSession.getContentId();
final boolean recordOnRepository = contentId != null
&& contentId.equalsIgnoreCase("repositoryRecorder");
recorderUrl = contentSession.getHttpServletRequest().getScheme()
+ "://" + config.getHandlerAddress() + ":"
+ contentSession.getHttpServletRequest().getServerPort();
handlerUrl = recorderUrl
+ contentSession.getHttpServletRequest().getContextPath();
cpbWindows = new CpbWindows(handlerUrl);
mediaPipeline = contentSession.getMediaPipelineFactory().create();
contentSession.releaseOnTerminate(mediaPipeline);
rateLimiter = mediaPipeline.newGStreamerFilter(
"videorate max-rate=15 average-period=200000000").build();
mirrorFilter = mediaPipeline.newGStreamerFilter("videoflip method=4")
.build();
chromaFilter = mediaPipeline.newChromaFilter(
new WindowParam(100, 10, 500, 400)).build();
pointerDetectorAdvFilter = mediaPipeline.newPointerDetectorAdvFilter(
new WindowParam(5, 5, 50, 50)).build();
pointerDetectorAdvFilter.addWindow(cpbWindows.start);
activeWindow = Windows.START;
faceOverlayFilter = mediaPipeline.newFaceOverlayFilter().build();
rateLimiter.connect(mirrorFilter);
mirrorFilter.connect(pointerDetectorAdvFilter);
pointerDetectorAdvFilter.connect(chromaFilter);
chromaFilter.connect(faceOverlayFilter);
pointerDetectorAdvFilter.addWindow(cpbWindows.fiware);
pointerDetectorAdvFilter
.addWindowInListener(new MediaEventListener<WindowInEvent>() {
@Override
public void onEvent(WindowInEvent event) {
try {
Windows windowId = Windows.valueOf(event
.getWindowId());
switch (windowId) {
case DK:
setDK();
break;
case FIWARE:
break;
case MARIO:
setMario();
break;
case SF:
setSF();
break;
case SONIC:
setSonic();
break;
case START:
addRecorder(contentSession, recordOnRepository);
setStart();
break;
case TRASH:
case YOUTUBE:
setEnding(windowId, recordOnRepository);
break;
default:
break;
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
});
WebRtcEndpoint webRtcEndpoint = mediaPipeline.newWebRtcEndpoint()
.build();
webRtcEndpoint.connect(rateLimiter);
faceOverlayFilter.connect(webRtcEndpoint);
contentSession.start(webRtcEndpoint);
}
@Override
public ContentCommandResult onContentCommand(
WebRtcContentSession contentSession, ContentCommand contentCommand)
throws Exception {
if (contentCommand.getType().equalsIgnoreCase("calibrate")) {
pointerDetectorAdvFilter.trackColorFromCalibrationRegion();
}
return new ContentCommandResult(contentCommand.getData());
}
private void addRecorder(WebRtcContentSession contentSession,
boolean repositoryRecorder) {
itemId = "campus-party-" + Calendar.getInstance().getTimeInMillis();
if (repositoryRecorder) {
RepositoryItem repositoryItem = contentSession.getRepository()
.createRepositoryItem(itemId);
RepositoryHttpRecorder recorder = repositoryItem
.createRepositoryHttpRecorder();
getLogger().info(
"repositoryRecorderUrl + recorder.getURL()" + recorderUrl
+ recorder.getURL());
recorderEndpoint = mediaPipeline.newRecorderEndpoint(
recorderUrl + recorder.getURL()).build();
} else {
recorderEndpoint = mediaPipeline.newRecorderEndpoint(
"file:///tmp/" + itemId).build();
}
faceOverlayFilter.connect(recorderEndpoint);
}
private void setStarWars() {
faceOverlayFilter.setOverlayedImage(handlerUrl
+ "/img/masks/darthvader.png", -0.5F, -0.5F, 1.7F, 1.7F);
chromaFilter
.setBackground(handlerUrl + "/img/background/deathstar.jpg");
}
private void setPirates() {
faceOverlayFilter.setOverlayedImage(handlerUrl + "/img/masks/jack.png",
-0.4F, -0.4F, 1.7F, 1.7F);
chromaFilter.setBackground(handlerUrl + "/img/background/pirates.jpg");
}
private void setStart() {
pointerDetectorAdvFilter.clearWindows();
pointerDetectorAdvFilter.addWindow(cpbWindows.fiware);
pointerDetectorAdvFilter.addWindow(cpbWindows.mario);
pointerDetectorAdvFilter.addWindow(cpbWindows.dk);
pointerDetectorAdvFilter.addWindow(cpbWindows.sf);
pointerDetectorAdvFilter.addWindow(cpbWindows.sonic);
recorderEndpoint.record();
}
private void checkFirstTime() {
if (activeWindow.equals(Windows.START)) {
pointerDetectorAdvFilter.addWindow(cpbWindows.trash);
pointerDetectorAdvFilter.addWindow(cpbWindows.youtube);
}
}
private boolean checkEasterEggs() {
boolean isEasterEgg = false;
if (count % 20 == 0) {
// Each 20 times (20, 40, ...) Darth Vader hat/background is
// shown
setStarWars();
isEasterEgg = true;
} else if (count % 10 == 0) {
// Each 10 times (10, 30, ...) the Jack Sparrow hat/background is
// shown
setPirates();
isEasterEgg = true;
}
count++;
return isEasterEgg;
}
private void setSF() throws URISyntaxException {
if (!activeWindow.equals(Windows.SF) && !checkEasterEggs()) {
faceOverlayFilter.setOverlayedImage(handlerUrl
+ "/img/masks/sf.png", -0.35F, -0.5F, 1.6F, 1.6F);
chromaFilter.setBackground(handlerUrl + "/img/background/sf.jpg");
checkFirstTime();
activeWindow = Windows.SF;
}
}
private void setMario() throws URISyntaxException {
if (!activeWindow.equals(Windows.MARIO) && !checkEasterEggs()) {
chromaFilter
.setBackground(handlerUrl + "/img/background/mario.jpg");
// Mario Easter Egg (a different mask each time)
if (mario % 2 == 0) {
faceOverlayFilter.setOverlayedImage(handlerUrl
+ "/img/masks/mario-wings.png", -0.35F, -1.2F, 1.6F,
1.6F);
} else {
faceOverlayFilter.setOverlayedImage(handlerUrl
+ "/img/masks/mario.png", -0.3F, -0.6F, 1.6F, 1.6F);
}
mario++;
checkFirstTime();
activeWindow = Windows.MARIO;
}
}
private void setDK() throws URISyntaxException {
if (!activeWindow.equals(Windows.DK) && !checkEasterEggs()) {
faceOverlayFilter.setOverlayedImage(handlerUrl
+ "/img/masks/dk.png", -0.35F, -0.5F, 1.6F, 1.6F);
chromaFilter.setBackground(handlerUrl + "/img/background/dk.jpg");
checkFirstTime();
activeWindow = Windows.DK;
}
}
private void setSonic() throws URISyntaxException {
if (!activeWindow.equals(Windows.SONIC) && !checkEasterEggs()) {
faceOverlayFilter.setOverlayedImage(handlerUrl
+ "/img/masks/sonic.png", -0.5F, -0.5F, 1.7F, 1.7F);
chromaFilter
.setBackground(handlerUrl + "/img/background/sonic.jpg");
checkFirstTime();
activeWindow = Windows.SONIC;
}
}
private void setEnding(Windows windowId, boolean recordOnRepository) {
chromaFilter.unsetBackground();
pointerDetectorAdvFilter.clearWindows();
pointerDetectorAdvFilter.addWindow(cpbWindows.fiware);
faceOverlayFilter.unsetOverlayedImage();
pointerDetectorAdvFilter.addWindow(cpbWindows.start);
activeWindow = Windows.START;
recorderEndpoint.release();
if (windowId.equals(Windows.YOUTUBE)) {
String recordUrl = handlerUrl
+ (recordOnRepository ? "/playerRepository/"
: "/cpbPlayer/") + itemId;
getLogger().info("recordUrl " + recordUrl);
Videos.upload(
recordUrl,
PLAYLIST_TOKEN,
newArrayList("FI-WARE", "Kurento", "FUN-LAB", "GSyC",
"URJC", "Campus Party", "WebRTC",
"Software Engineering", "Augmented Reality",
"Computer Vision", "Super Mario", "Sonic",
"Street Fighter", "Donkey Kong"));
}
}
}
class CpbWindows {
// Enumeration of windows
enum Windows {
START, SF, DK, MARIO, SONIC, TRASH, YOUTUBE, FIWARE
}
// Windows instances
public PointerDetectorWindowMediaParam start;
public PointerDetectorWindowMediaParam sf;
public PointerDetectorWindowMediaParam mario;
public PointerDetectorWindowMediaParam dk;
public PointerDetectorWindowMediaParam sonic;
public PointerDetectorWindowMediaParam trash;
public PointerDetectorWindowMediaParam youtube;
public PointerDetectorWindowMediaParam fiware;
public CpbWindows(String handlerUrl) throws URISyntaxException {
start = new PointerDetectorWindowMediaParam(Windows.START.toString(),
100, 100, 280, 380);
start.setImage(handlerUrl + "/img/buttons/start.png");
mario = new PointerDetectorWindowMediaParam(Windows.MARIO.toString(),
100, 100, 540, 0);
mario.setImage(handlerUrl + "/img/buttons/mario.png");
dk = new PointerDetectorWindowMediaParam(Windows.DK.toString(), 100,
100, 540, 126);
dk.setImage(handlerUrl + "/img/buttons/dk.png");
sf = new PointerDetectorWindowMediaParam(Windows.SF.toString(), 100,
100, 540, 252);
sf.setImage(handlerUrl + "/img/buttons/sf.png");
sonic = new PointerDetectorWindowMediaParam(Windows.SONIC.toString(),
100, 100, 540, 380);
sonic.setImage(handlerUrl + "/img/buttons/sonic.png");
youtube = new PointerDetectorWindowMediaParam(
Windows.YOUTUBE.toString(), 100, 100, 0, 380);
youtube.setImage(handlerUrl + "/img/buttons/youtube.png");
trash = new PointerDetectorWindowMediaParam(Windows.TRASH.toString(),
100, 100, 0, 190);
trash.setImage(handlerUrl + "/img/buttons/trash.png");
fiware = new PointerDetectorWindowMediaParam(Windows.FIWARE.toString(),
40, 180, 230, 0);
fiware.setImage(handlerUrl + "/img/buttons/fiware2.png");
}
}