Free now2sdk Core is completely free — no license key required   See what's included →
SDK Modules Docs Release Notes Pricing GitHub
Get the SDK →

LStinger Reference Manual & Transition Clip Guide

The LStinger class is the transition clip management engine of the now2sdk framework, derived from the LObject stream source. It is designed to pre-load a video file or an image sequence containing Alpha Transparency channels (e.g. VP9, ProRes 4444, PNG sequences), caching scaled frames directly in system memory as YUVA420p textures to enable instant transparent overlay transitions (stinger transitions).


1. Frame Loading & Transparent Playout Architecture

graph TD
    A[load path] --> B{Path contains % ?}
    
    B -->|Yes| C[Configure FFmpeg image2 demuxer for sequence]
    B -->|No| D[Configure standard video demuxer]
    
    C --> E[avformat_open_input & find stream]
    D --> E
    
    E --> F[Alloc SwsContext for target dimensions]
    F --> G[Scale & Convert raw frames to YUVA420P]
    G --> H[Cache AVFrame* inside m_frames vector]
    
    I[playOnce trigger] --> J[Spawn playbackLoop Thread]
    J --> K[Step through cached frames sequentially]
    K --> L{Licensed?}
    L -->|No| M[Overlay Watermark on-the-fly]
    L -->|Yes| N[No watermark bypass]
    M --> O[Call distributeVideoFrame to downstream mixers/preview]
    N --> O

Key Technical Details:


2. API Reference & Public Methods

All public methods available in the LStinger class:

📌 Licensing Controls

bool setLicense(const std::string& licenseKey);

Registers a license key for the stinger instance. Returns true if valid.

bool isLicensed() const;

Checks if the stinger module is licensed on the host system.


📌 Clip Loading & Lifecycle

bool load(const std::string& path, int targetWidth, int targetHeight, double fps = 25.0);

Decompresses, scales, and caches frames from the target path.

void clear();

Clears the frame memory cache and releases allocated AVFrame objects. Called automatically in the destructor.


📌 Playback Control

void playOnce();

Triggers playout once. Spawns a background thread to sequentially distribute frames at the target frame rate.

void stop();

Terminates the active playback loop and joins the background thread.


📌 Status & Configuration Getters/Setters

Since LStinger is a lightweight transition source, it does not implement a setProps(key, value) dictionary interface. Instead, settings are configured directly using the following type-safe C++ methods:

Method Return / Param Type Description
isLoaded() bool Returns true if frames are currently cached in memory.
getFrameCount() int Returns the total number of frames in the loaded transition clip.
setFPS(fps) double (param) Sets/overrides the playout frame rate target.
getFPS() double Returns the current playout frame rate target.
statusGet(status) int& (out param) Sets status value: 1 if playing, 0 if idle.

3. Transition Overlay Integration Example

This example demonstrates how to set up LStinger to overlay a transition graphic dynamically on top of a program feed. It uses a custom mixer or switcher to overlay the stinger frames over a live camera during a scene change.

#include "LStinger.h"
#include "LLive.h"
#include "LPreview.h"
#include <iostream>

class TransitionManager {
public:
    TransitionManager() 
        : m_stinger(new LStinger()),
          m_liveFeed(new LLive()),
          m_preview(new LPreview())
    {
        // 1. Initialize license
        m_stinger->setLicense("YOUR_LICENSE_KEY_HERE");

        // 2. Configure camera ingest source (1080p50)
        videoFormatProps format;
        format.setVideoFormat = vF::HD1080_50p;
        m_liveFeed->setVideoFormat(format);
        m_liveFeed->Start();

        // 3. Pre-load transparent overlay clip (e.g. 150 frames, 3-second transition)
        // Loading is synchronous, pre-loading into RAM cache
        bool success = m_stinger->load("/var/broadcasting/transitions/swipe_%03d.png", 1920, 1080, 50.0);
        if (success) {
            std::cout << "[Stinger] Loaded successfully! Total Frames: " 
                      << m_stinger->getFrameCount() << std::endl;
        } else {
            std::cerr << "[Stinger] Failed to load image sequence!" << std::endl;
        }

        // 4. Set preview target
        m_preview->previewEnable(nullptr, true, true);
        m_preview->previewObject(m_liveFeed); // Initially preview live feed
    }

    ~TransitionManager() {
        m_stinger->stop();
        m_stinger->clear();
        m_liveFeed->Stop();
        
        delete m_preview;
        delete m_stinger;
        delete m_liveFeed;
    }

    // Triggered when a transition is requested
    void triggerStingerCut() {
        if (!m_stinger->isLoaded()) return;

        std::cout << "[Transition] Triggering stinger overlay..." << std::endl;

        // Route the preview to show the transparent stinger overlay
        m_preview->previewObject(m_stinger);

        // Start playout of stinger frames (runs in background thread)
        m_stinger->playOnce();

        // Wait for the cut point (e.g., middle of transition, frame 75 of 150)
        // In a real broadcast switcher, this triggers the background scene cut.
        std::thread([this]() {
            int cutPointMs = (75.0 / 50.0) * 1000; // 1.5 seconds offset
            std::this_thread::sleep_for(std::chrono::milliseconds(cutPointMs));
            
            std::cout << "[Transition] CUT POINT REACHED - Performing background source switch!" << std::endl;
            // Switch cameras/sources here...
            
            // Wait for transition to fully complete (150 frames = 3 seconds total)
            int remainingMs = ((150 - 75) / 50.0) * 1000;
            std::this_thread::sleep_for(std::chrono::milliseconds(remainingMs));
            
            std::cout << "[Transition] Transition complete. Restoring camera preview." << std::endl;
            // Route preview back to program camera
            m_preview->previewObject(m_liveFeed);
        }).detach();
    }

private:
    LStinger* m_stinger;
    LLive* m_liveFeed;
    LPreview* m_preview;
};