Dear!
We create this file in JAVA, its reach 90% our needs BUT we are facing an issue, webcams are random positioned and if attach 4 streams mixer stop to work without error on logs file.
Could you help me please?
// 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 com.flashphoner.sdk.setting.Settings;
// 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_IN = Settings.MIXER_VIDEO_DESKTOP_LAYOUT_INLINE_PADDING.getValue().intValue();
    
    @Override
    public IVideoMixerLayout.Layout[] computeLayout(YUVFrame[] yUVFrameArr, String[] strArr, int canvasWidth, int canvasHeight) {
        
        if (yUVFrameArr.length == 0) {
            return new IVideoMixerLayout.Layout[0];
        }
        
        ArrayList<IVideoMixerLayout.Layout> layout = new ArrayList<>();
        
        int layoutWidth = 0;
        int layoutHeight = 0;
        int first = 0;
        
        if(yUVFrameArr.length == 1)
        {
            Point ltPoint = new Point(PADDING_IN, PADDING_IN);
            layoutWidth = canvasWidth - 2*PADDING_IN;
            layoutHeight = Math.min((int)(layoutWidth*9.0d/16.0d), canvasHeight - 2*PADDING_IN);
            layout.add(new IVideoMixerLayout.Layout(ltPoint, new Dimension(layoutWidth, layoutHeight), yUVFrameArr[0]));
        }
        else { // length >= 2
            for (int c = 0; c < yUVFrameArr.length; c++) {
            
                // Set starting point of the picture
                Point currentPoint = new Point();
                
                /*Point prevPoint = new Point();
                Dimension prevDimension = new Dimension();
                if (layout.size() > 1) {
                    // Find previous picture location to calculate next one
                    prevPoint.setLocation(layout.get(c - 1).getPoint());
                    prevDimension.setSize(layout.get(c - 1).getDimension());
                }*/
                
                if (strArr[c].toLowerCase().startsWith("d") == true) { //c == first
                    currentPoint = new Point((int)(canvasWidth * 0.25d) + PADDING_IN, PADDING_IN); 
                    layoutWidth = (int)(canvasWidth * 0.75d) - 2*PADDING_IN;
                    layoutHeight = Math.min((int)(layoutWidth*9.0d/16.0d), canvasHeight - 2*PADDING_IN);
                } else {                    
                    //currentPoint = new Point( PADDING_IN, (int) (prevPoint.getY() + prevDimension.getHeight() + PADDING_IN) );
                    layoutWidth = (int)(canvasWidth * 0.25d) - 2*PADDING_IN;
                    layoutHeight = Math.min((int) ((layoutWidth*9.0d/16.0d)), (int) ((canvasHeight - (yUVFrameArr.length - 1) * PADDING_IN)/ (double) (yUVFrameArr.length - 1)));
                    currentPoint = new Point( PADDING_IN, (int) (layoutHeight*c + PADDING_IN) );
                }
                
                // Create the picture layout passing starting point, dimensions and raw picture YUV frames
                layout.add(new IVideoMixerLayout.Layout(currentPoint, new Dimension(layoutWidth, layoutHeight), yUVFrameArr[c]));
            }
        }
        // Return pictures layouts calculated as array
        return layout.toArray(new IVideoMixerLayout.Layout[layout.size()]);
    } 
    
}