...
Code Block |
---|
language | java |
---|
theme | RDark |
---|
title | TestLayout.java |
---|
collapse | true |
---|
|
// Package name should be strictly defined as com.flashphoner.mixerlayout
package com.flashphoner.mixerlayout;
// Import mixer layout interface
import com.flashphoner.sdk.media.IVideoMixerLayout;
// Import YUV frame description
import com.flashphoner.sdk.media.YUVFrame;
// Import Java packages to use
import java.awt.*;
import java.util.ArrayList;
/**
* Custom mixer layout implementation example
*/
public class TestLayout implements IVideoMixerLayout {
// Pictures padding, should be even (or zero if no padding needed)
private static final int PADDING = 4;
/**
* 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) {
// Declare picture layouts list to fill
ArrayList<IVideoMixerLayout.Layout> layout = new ArrayList<>();
// Find canvas center height
int canvasCenter = canvasHeight / 2;
// Find frame center
int frameCenter = canvasCenter - (canvasHeight / yuvFrames.length) / 2;
// Find every picture dimensions (this are the same for all the pictures because this is grid layout)
int layoutWidth = canvasWidth / yuvFrames.length - PADDING;
int layoutHeight = canvasHeight / yuvFrames.length;
// Iterate through incoming stream pictures array
// Note: streams pictures order corresponds to stream names array, use this to reorder pictures if needed
for (int c = 0; c < yuvFrames.length; c++) {
// Use Java AWT Point and Dimension
Point prevPoint = new Point();
Dimension prevDimension = new Dimension();
if (layout.size() > 0) {
// Find previous picture location to calculate next one
prevPoint.setLocation(layout.get(c - 1).getPoint());
prevDimension.setSize(layout.get(c - 1).getDimension());
}
// Set starting point of the picture
Point currentPoint = new Point((int) (prevPoint.getX() + prevDimension.getWidth() + PADDING),
frameCenter);
// Create the picture layout passing starting point, dimensions and raw picture YUV frames
layout.add(new IVideoMixerLayout.Layout(currentPoint, new Dimension(layoutWidth,
layoutHeight), yuvFrames[c]));
}
// Return pictures layouts calculated as array
return layout.toArray(new IVideoMixerLayout.Layout[layout.size()]);
}
} |
To support caption text location above or below stream picture, a special Box class should be used to calculate pictures placement since build 5.2.878, for example
Code Block |
---|
language | java |
---|
theme | RDark |
---|
title | TestLayoutWithBox.java |
---|
collapse | true |
---|
|
// Package name should be strictly defined as com.flashphoner.mixerlayout
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;
/**
* Custom mixer layout implementation example
*/
public class TestLayout implements IVideoMixerLayout {
// Pictures padding, should be even (or zero if no padding needed)
private static final int PADDING = 4;
/**
* Function to compute layout, will be called by mixer before encoding output stream picture
* This example computes one-line 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);
// Find every picture dimensions (this are the same for all the pictures because this is grid layout)
int frameBoxWidth = canvasWidth / yuvFrames.length - PADDING;
int frameBoxHeight = canvasHeight / yuvFrames.length;
// Container to place stream pictures
Box container = new Box(mainBox, canvasWidth, frameBoxHeight);
container.setPosition(BoxPosition.CENTER);
// Iterate through incoming stream pictures array
// Note: streams pictures order corresponds to stream names array, use this to reorder pictures if needed
boolean firstFrame = true;
for (int c = 0; c < yuvFrames.length; c++) {
// Stream picture parent rectangle
// This rectangle can include stream caption if mixer_text_outside_frame setting is enabled
Box frameBox = new Box(container, frameBoxWidth, (int)container.getSize().getHeight());
frameBox.setPosition(BoxPosition.INLINE_HORIZONTAL_CENTER);
// Add padding for subsequent pictures
if (!firstFrame) {
frameBox.setPaddingLeft(PADDING);
}
firstFrame = false;
// Compute picture frame placement including stream caption text
Box frame = Box.computeBoxWithFrame(frameBox, yuvFrames[c]);
// Adjust picture to the parent rectangle
frame.fillParent();
}
// 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) {
}
} |
Main Box class methods:
Code Block |
---|
language | java |
---|
theme | RDark |
---|
title | Box methods available |
---|
collapse | true |
---|
|
/**
* Set paddings
* @param padding padding value to set
**/
public void setPaddingLeft(int paddingLeft);
public void setPaddingRight(int paddingRight);
public void setPaddingTop(int paddingTop);
public void setPaddingBottom(int paddingBottom);
/**
* Set position
* @param position box position to set
**/
public void setPosition(BoxPosition position);
/**
* Compute location and size of this box and all of it's content
* @param layouts aggregator collection to put computed layouts to
*/
public void computeLayout(ArrayList<IVideoMixerLayout.Layout> layouts);
/**
* Compute box location inside the parent Box including caption text placement
* @param parent parent box
* @param yuvFrame frame to compute location
* @return frame with location computed
*/
public static Box computeBoxWithFrame(Box parent, YUVFrame yuvFrame);
/**
* Scale box to the size closest to size of the parent, preserving aspect ratio
*/
public void fillParent(); |
Possible positions to place Box object:
Code Block |
---|
language | java |
---|
theme | RDark |
---|
title | BoxPosition |
---|
collapse | true |
---|
|
public enum BoxPosition {
//attach box to the left
LEFT,
//attach box to the right
RIGHT,
//attach box to the top
TOP,
//attach box to the bottom
BOTTOM,
//center box in the parent box
CENTER,
//bottom and center box in the parent box
BOTTOM_CENTER,
//top and center box in the parent box
TOP_CENTER,
//attach box to the right-top corner of left adjoining box (in the same parent box)
INLINE_HORIZONTAL,
//same as INLINE_HORIZONTAL but additionally adds vertical CENTER
INLINE_HORIZONTAL_CENTER,
//attach box to the left-bottom corner of upper adjoining box (in the same parent box)
INLINE_VERTICAL,
//same as INLINE_VERTICAL but additionally adds horizontal CENTER
INLINE_VERTICAL_CENTER
} |
Then the class should be complied into byte code. To do this, create folder tree accordind to TestLayout class package name
...