CasparCG tips for HTML templates optimization

Hi,
Regarding casparcg and html templates-
I’ve used only WEBP images around my template,
When I play on caspar it’s stuttering, I was wondering if you guys have any tips on how to optimize both the scene and the caspar engine to utilize the GPU (I got an nvidia A5000) on this machine,

I’ve set the

<html>
    <enable-gpu>true</enable-gpu>
</html>

any other thing I might have missed? it’s a windows 10 machine with 64gb ram running at 29.97.
Template is configure to 30fps (not sure if its affecting anything)

any idea would be much appreciated

Thanks!

Before giving you a more specific recommendation, need a bit more information about your setup. The stuttering could be caused by a number of things, so seeing your exact configuration will help narrow it down.

Could you please share the following?

  • A sample of your HTML template code
  • Your CasparCG channel configuration from your casparcg.config file.

Thanks!

I think this is related to the new CEF version that 2.4 uses. There’s an open issue on GitHub:
https://github.com/CasparCG/server/issues/1583
It only affects templates with WebM files when running using GPU acceleration.

Thanks for the reply,
The channel section of the config is below.
as for the template code, I know it might make it more difficult, but i’m not sure the customer would like if I shared their designs.

I can tell you that I have a sequence of ~100 webp images at half-HD res (960x540)
I build more complicated templates (with >100 images, and it was running fine at 25fps)
The new template is less heavy than previous ones I built, yet it’s stuttering at 29.97fps

I was wondering if I need to add casparcg to nvidia’s program list (nvidia control panel > manage 3d settings > program settings) or anything like that…

 <channels>
   
        <channel>
            <video-mode>1080p5994</video-mode>
            <consumers>
	            <decklink>
		            <device>1</device>
	            </decklink>
            </consumers>
        </channel>

        <channel>
            <video-mode>1080p5994</video-mode>
            <consumers>
	            <decklink>
	                <device>2</device>
	            </decklink>
            </consumers>
        </channel>

        <channel>
            <video-mode>1080p5994</video-mode>
            <consumers>
	            <decklink>
	                <device>3</device>
	            </decklink>
            </consumers>
        </channel>

    </channels>

If you are using the default settings, then change the power profile either for the app or as the default config (look for the “Power management mode” and “Texture filtering - Quality” settings):

Also on workstation GPUs you would want to change the usage mode to “Dedicate to graphics tasks” under Workstation > Manage GPU Utilization, though your card most likely doesn’t get hit that hard by HTML templates.

If you’re just animating images, it should run smoothly.
If you think it is related to 29.97fps, you can test your new template on the 25fps channel to make sure. You can also try with Enable GPU false.

GPU Utilization:
yes you can try with it to ensure the dedicated GPU is used and is configured for maximum performance.

  • Preferred graphics processor: High-performance NVIDIA processor
  • Power management mode: Prefer maximum performance
  • Vertical sync: Off (CasparCG handles its own synchronization)

HTML Template:
how are you animating ? have you tried with requestAnimationFrame() ?

just for the testing, run this sample template in your setup and see if stuttering.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Slider</title>
    <style>
        body {
            background-color: transparent;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            overflow: hidden;
            font-family: 'Inter', sans-serif;
            color: white;
        }

        .slider-container {
            display: flex;
            flex-direction: column;
            gap: 40px;
            width: 100%;
            height: 100%;
            justify-content: center;
            align-items: center;
        }

        .slider {
            width: 90%;
            height: 200px;
            overflow: hidden;
            border-radius: 16px;
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2), 0 0 20px rgba(0, 0, 0, 0.1);
            position: relative;
        }

        .image-strip {
            display: flex;
            height: 100%;
            position: absolute;
            will-change: transform;
        }

        .image-strip img {
            height: 100%;
            width: auto;
            object-fit: cover;
            border-radius: 16px;
            margin-right: 20px;
        }
    </style>
</head>
<body>
    <div class="slider-container">
        <div class="slider" id="slider1">
            <div class="image-strip" id="strip1">
                <img src="https://placehold.co/400x200/4e89ae/d2d7df?text=Image+1-1" alt="Image 1-1">
                <img src="https://placehold.co/400x200/77c9d4/ffffff?text=Image+1-2" alt="Image 1-2">
                <img src="https://placehold.co/400x200/5e8d89/f0f6f5?text=Image+1-3" alt="Image 1-3">
                <img src="https://placehold.co/400x200/98b39a/fff8e1?text=Image+1-4" alt="Image 1-4">
                <img src="https://placehold.co/400x200/a3cc8e/4a5b4f?text=Image+1-5" alt="Image 1-5">
            </div>
        </div>

        <div class="slider" id="slider2">
            <div class="image-strip" id="strip2">
                <img src="https://placehold.co/400x200/4e89ae/d2d7df?text=Image+2-1" alt="Image 2-1">
                <img src="https://placehold.co/400x200/77c9d4/ffffff?text=Image+2-2" alt="Image 2-2">
                <img src="https://placehold.co/400x200/5e8d89/f0f6f5?text=Image+2-3" alt="Image 2-3">
                <img src="https://placehold.co/400x200/98b39a/fff8e1?text=Image+2-4" alt="Image 2-4">
                <img src="https://placehold.co/400x200/a3cc8e/4a5b4f?text=Image+2-5" alt="Image 2-5">
            </div>
        </div>
    </div>

    <script>
        const strips = document.querySelectorAll('.image-strip');
        const positions = new Map();
        let animationFrameId;

        function init() {
            strips.forEach(strip => {
                positions.set(strip.id, 0);
            });
        }

        function updateStrips() {
            strips.forEach(strip => {
                let currentPos = positions.get(strip.id);
                const direction = (strip.id === 'strip1') ? -1 : 1;
                const speed = 0.5 * direction;

                currentPos += speed;

                const stripWidth = strip.scrollWidth;
                const containerWidth = strip.parentElement.clientWidth;

                if (direction === -1) {
                    if (Math.abs(currentPos) >= (stripWidth - containerWidth)) {
                        currentPos = 0;
                    }
                } else if (direction === 1) {
                    if (currentPos > 0) {
                        currentPos = (stripWidth - containerWidth) * -1;
                    }
                }

                positions.set(strip.id, currentPos);
                strip.style.transform = `translateX(${currentPos}px)`;
            });

            animationFrameId = requestAnimationFrame(updateStrips);
        }

        window.play = function() {
            // if (!animationFrameId) {
            //     updateStrips();
            // }
        };

        window.stop = function() {
            if (animationFrameId) {
                cancelAnimationFrame(animationFrameId);
                animationFrameId = null;
            }
        };

        window.next = function() {};
        window.update = function(data) {};

        init();
        updateStrips();
    </script>
</body>
</html>