...
With this custom layout, mixer output stream for three input streams will look like:
Cropping pictures in custom layout
To crop a picture around a central point like CropNoPaddingGridLayout, use Box.fillParentNoScale() instead of Box.fillParent() method. The following example places two pictures by name with cropping around center:
Code Block | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
package com.flashphoner.mixerlayout;
// Import mixer layout interface
import com.flashphoner.media.mixer.video.presentation.BoxPosition;
import com.flashphoner.sdk.media.IVideoMixerLayout;
// Import YUV frame description
import com.flashphoner.sdk.media.YUVFrame;
// Import Box class for picture operations
import com.flashphoner.media.mixer.video.presentation.Box;
// Import MixerConfig class
import com.flashphoner.server.commons.rmi.data.impl.MixerConfig;
// Import Java packages to use
import java.awt.*;
import java.util.ArrayList;
public class SideBySideLayout implements IVideoMixerLayout {
// Owner's stream name
private static final String USERFOR = "user_for";
// Challenger's stream name
private static final String USERAGAINST = "user_against";
/**
* Function to compute layout, will be called by mixer before encoding output stream picture
* This example computes grid layout
* @param yuvFrames - incoming streams raw pictures array in YUV format
* @param strings - incoming streams names array
* @param canvasWidth - mixer output picture canwas width
* @param canvasHeight - mixer output picture canwas heigth
* @return array of pictures layouts
*/
@Override
public Layout[] computeLayout(YUVFrame[] yuvFrames, String[] strings, int canvasWidth, int canvasHeight) {
// This object represents mixer canvas
Box mainBox = new Box(null, canvasWidth, canvasHeight);
// Container to place CHALLENGER stream pictures
Box userForContainer = new Box(mainBox, canvasWidth / 2, canvasHeight);
userForContainer.setPosition(BoxPosition.LEFT);
// Container to place OWNER stream pictures
Box userAgainstContainer = new Box(mainBox, canvasWidth / 2, canvasHeight);
userAgainstContainer.setPosition(BoxPosition.RIGHT);
// Iterate through incoming stream pictures array
for (int c = 0; c < yuvFrames.length; c++) {
String name = strings[c];
Box container;
// Chhose container depending on stream name
if (name.contains(USERFOR)) {
container = userForContainer;
} else if (name.contains(USERAGAINST)) {
container = userAgainstContainer;
} else {
// Wrong stream name
continue;
}
// Fill the container by the stream picture
Box frameBox = Box.computeBoxWithFrame(container, yuvFrames[c]);
frameBox.fillParentNoScale();
}
// Prepare an array to return layout calculated
ArrayList<IVideoMixerLayout.Layout> layout = new ArrayList<>();
// Calculate mixer layout
mainBox.computeLayout(layout);
// Return the result
return layout.toArray(new IVideoMixerLayout.Layout[layout.size()]);
}
/**
* The function for internal use. Must be overriden.
*/
@Override
public void setConfig(MixerConfig mixerConfig) {
}
}
|
Mixer layout management while creating mixer
...