Wide Channel in single Decklink SDI output

Hello, i need to create a crwal text to be viewed into a led.
The led size is around 13.000 x 150 px.
My idea is to create a channel with a custom size and run the html scene inside it.
I need to sent the video to the led data processor using 1 sdi decklink channel.
i tried to use subregion but i can’t set multiple subregions in config file. (it could be nice to have this features).
The other thing is to create 2 channel, and use channel router + crop & transtorm to include all portion of crawl into HD channel.
Does anyone have a better solution?

Thanks,
Andrea

The channel route is the best solution… you make a custom resolution channel then route each slice to a second channel.

I’ve recently had to code a function to make the strips (either vertically or horizontally)
If you program yourself, you can get an idea from these functions in C#:

public class Slice
{
    private double _width;
    private double _height;

    private Thickness _crop;

    private double _targetWidth = 0;
    private double _targetHeight = 0;
    private double _targetX = 0;
    private double _targetY = 0;

    public Slice(double width, double height)
    {
        _width = width;
        _height = height;
    }

    public void SetTarget(double width, double height, double x, double y)
    {
        _targetWidth = width;
        _targetHeight = height;
        _targetX = x;
        _targetY = y;
    }

    public void SetCrop(double left, double top, double right, double bottom)
    {
        var crop_left = left / _width;
        var crop_right = right / _width;
        var crop_top = top / _height;
        var crop_bottom = bottom / _height;
        _crop = new Thickness(crop_left, crop_top, crop_right, crop_bottom);
    }

    public Thickness Crop
    {
        get
        {
            return _crop;
        }
    }

    public Fill Fill
    {
        get
        {
            var pos_x = _targetX / _targetWidth;
            var pos_y = _targetY / _targetHeight;
            var size_x = _width / _targetWidth;
            var size_y = _height / _targetHeight;
            return new Fill(pos_x,pos_y,size_x, size_y);
        }
    } 
}

public struct Fill
{
    public Fill()
    {
        _PanX = 0;
        _PanY = 0;
        _ZoomX = 1;
        _ZoomY = 1;
    }

    public Fill(double panX, double panY, double zoomX, double zoomY)
    {
        _PanX = panX;
        _PanY = panY;
        _ZoomX = zoomX;
        _ZoomY = zoomY;
    }

    private double _PanX;
    private double _PanY;
    private double _ZoomX;
    private double _ZoomY;

    public double PanX => _PanX;
    public double PanY => _PanY;
    
    public double ZoomX => _ZoomX;
    public double ZoomY => _ZoomY;
}

public static List<Slice> GetScreenSlices(double sourceWidth, double sourceHeight, double targetWidth, double targetHeight, double slices, bool vertical = false)
{
    var sliceWidth = !vertical ? sourceWidth / slices : sourceWidth;
    var sliceHeight = vertical ? sourceHeight / slices : sourceHeight;
    List<Slice> sliceList = [];
    for (int s = 0; s < slices; s++)
    {
        var slice = new Slice(sourceWidth, sourceHeight);
        sliceList.Add(slice);
        double x = 0;
        double y = 0;
        if (vertical)
        {
            x = sliceWidth * s;
            y = 0 - sliceHeight * s;
        }
        else
        {
            x = 0 - sliceWidth * s;
            y = sliceHeight * s;
        }
        slice.SetTarget(targetWidth, targetHeight, x, y);
        var crop_x = vertical ? 0 : sliceWidth * s;
        var crop_y = vertical ? sliceHeight * s : 0;
        var crop_w = vertical ? sliceWidth : crop_x + sliceWidth;
        var crop_h = vertical ? crop_y + sliceHeight : sliceHeight;
        slice.SetCrop(crop_x, crop_y, crop_w, crop_h);
    }

    return sliceList;
}

internal void SetupMainLedScreen()
{
    Rect MainLED = new(0, 0, 2962, 540);
    Rect MainLED_channel = new(0, 0, 1920, 1080);
    var main = App.Settings.MainLEDSetting;
    var main_route = 2;

    App.Servers[main.Server].SendToAll($"CLEAR {main_route}");
    App.Servers[main.Server].SendToAll($"MIXER {main_route} CLEAR");

    var main_slices = GetScreenSlices(MainLED.Width, MainLED.Height, MainLED_channel.Width, MainLED_channel.Height, 2);
    var main_slice = 0;
    foreach (Slice slice in main_slices)
    {
        main_slice++;
        App.Servers[main.Server].SendToAll($"PLAY {main_route}-{main_slice} route://{main.Channel}");
        App.Servers[main.Server].SendToAll($"MIXER {main_route}-{main_slice} CROP {F(slice.Crop.Left)} {F(slice.Crop.Top)} {F(slice.Crop.Right)} {F(slice.Crop.Bottom)}");
        App.Servers[main.Server].SendToAll($"MIXER {main_route}-{main_slice} FILL {F(slice.Fill.PanX)} {F(slice.Fill.PanY)} {F(slice.Fill.ZoomX)} {F(slice.Fill.ZoomY)}");
    }
}
1 Like

Thanks Mauro,
I’ll try your slice code soon.

Andrea.