# Processing Filters Pack - Code Examples

# Overview

This page provides practical code examples for using the Processing Filters Pack, which includes:

  • Video Effects - 35+ real-time effects (text, graphics, color adjustments, denoise)
  • Video Mixer - 2-16 source mixing with PIP, alpha blending, chroma key
  • Chroma Key - Green/blue screen compositing

# Prerequisites

# C++ Projects

#include <dshow.h>
#include <streams.h>
#include "IVFEffects45.h"
#include "IVFVideoMixer.h"
#include "IVFChromaKey.h"

#pragma comment(lib, "strmiids.lib")

# C# Projects

using VisioForge.DirectShowAPI;
using VisioForge.DirectShowLib;
using System.Runtime.InteropServices;
using System.Drawing;

NuGet Packages:

  • VisioForge.DirectShowAPI
  • MediaFoundationCore

# Video Effects Examples

# Example 1: Basic Video Effect

Apply a single video effect to a source.

# C# Implementation

using System;
using System.Runtime.InteropServices;
using VisioForge.DirectShowAPI;
using VisioForge.DirectShowLib;

public class VideoEffectsBasicExample
{
    private IFilterGraph2 filterGraph;
    private IMediaControl mediaControl;
    private IBaseFilter sourceFilter;
    private IBaseFilter effectFilter;

    public void PlayWithEffect(string filename, IntPtr videoWindowHandle)
    {
        filterGraph = (IFilterGraph2)new FilterGraph();
        mediaControl = (IMediaControl)filterGraph;

        // Add source filter (e.g., File Source)
        filterGraph.AddSourceFilter(filename, "Source", out sourceFilter);

        // Add Video Effects filter
        effectFilter = FilterGraphTools.AddFilterFromClsid(
            filterGraph,
            Consts.CLSID_VFVideoEffects,
            "Video Effects");

        // Configure effect using IVFEffects45 interface
        var effects = effectFilter as IVFEffects45;
        if (effects != null)
        {
            // Enable Greyscale effect
            effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GREYSCALE, 1);

            // Set effect parameters (some effects require parameters)
            // effects.SetEffectParam(effectType, paramName, paramValue);
        }

        // Connect filters: Source → Effect → Renderer
        ICaptureGraphBuilder2 captureGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
        captureGraph.SetFiltergraph(filterGraph);

        // Render through effect filter
        captureGraph.RenderStream(null, MediaType.Video, sourceFilter, effectFilter, null);
        captureGraph.RenderStream(null, MediaType.Audio, sourceFilter, null, null);

        // Set up video window
        var videoWindow = (IVideoWindow)filterGraph;
        videoWindow.put_Owner(videoWindowHandle);
        videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings);

        // Run
        mediaControl.Run();

        Marshal.ReleaseComObject(captureGraph);
    }

    public void Stop()
    {
        mediaControl?.Stop();

        FilterGraphTools.RemoveAllFilters(filterGraph);

        if (sourceFilter != null) Marshal.ReleaseComObject(sourceFilter);
        if (effectFilter != null) Marshal.ReleaseComObject(effectFilter);
        if (mediaControl != null) Marshal.ReleaseComObject(mediaControl);
        if (filterGraph != null) Marshal.ReleaseComObject(filterGraph);
    }
}

# C++ Implementation

HRESULT ApplyVideoEffect(LPCWSTR filename)
{
    IGraphBuilder* pGraph = NULL;
    IBaseFilter* pSource = NULL;
    IBaseFilter* pEffect = NULL;
    IVFEffects45* pEffects = NULL;

    // Create filter graph
    HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
                                  IID_IGraphBuilder, (void**)&pGraph);
    if (FAILED(hr)) return hr;

    // Add source
    hr = pGraph->AddSourceFilter(filename, L"Source", &pSource);
    if (FAILED(hr)) goto cleanup;

    // Create Video Effects filter
    hr = CoCreateInstance(CLSID_VFVideoEffects, NULL, CLSCTX_INPROC_SERVER,
                         IID_IBaseFilter, (void**)&pEffect);
    if (FAILED(hr)) goto cleanup;

    hr = pGraph->AddFilter(pEffect, L"Video Effects");
    if (FAILED(hr)) goto cleanup;

    // Configure effect
    hr = pEffect->QueryInterface(IID_IVFEffects45, (void**)&pEffects);
    if (SUCCEEDED(hr))
    {
        // Enable greyscale
        pEffects->SetEffect(VF_VIDEO_EFFECT_GREYSCALE, 1);
        pEffects->Release();
    }

    // Connect filters and render...
    // (Use RenderStream or ConnectFilters)

cleanup:
    if (pEffect) pEffect->Release();
    if (pSource) pSource->Release();
    if (pGraph) pGraph->Release();

    return hr;
}

# Example 2: Multiple Effects Chain

Apply multiple effects simultaneously.

# C# Multiple Effects

public class MultipleEffectsExample
{
    public void ApplyMultipleEffects(IBaseFilter effectFilter)
    {
        var effects = effectFilter as IVFEffects45;
        if (effects != null)
        {
            // Enable multiple effects
            effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BRIGHTNESS, 1);
            effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_CONTRAST, 1);
            effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_SATURATION, 1);

            // Set parameters for each effect
            effects.SetEffectParam(
                VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BRIGHTNESS,
                "Value",
                50);  // Brightness value (0-100)

            effects.SetEffectParam(
                VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_CONTRAST,
                "Value",
                75);  // Contrast value (0-100)

            effects.SetEffectParam(
                VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_SATURATION,
                "Value",
                120);  // Saturation value (0-200)
        }
    }
}

# Example 3: Text Overlay

Add text logo overlay to video.

# C# Text Overlay

public void ApplyTextOverlay(IBaseFilter effectFilter)
{
    var effects = effectFilter as IVFEffects45;
    if (effects != null)
    {
        // Enable text logo effect
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO, 1);

        // Configure text parameters
        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO,
            "Text",
            "My Video Title");

        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO,
            "FontName",
            "Arial");

        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO,
            "FontSize",
            36);

        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO,
            "Color",
            ColorTranslator.ToWin32(Color.White));

        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO,
            "X",
            50);  // X position

        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO,
            "Y",
            50);  // Y position

        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO,
            "Transparent",
            0);  // Opaque

        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO,
            "Alpha",
            255);  // Fully opaque
    }
}

# Example 4: Image Overlay

Add graphic watermark or logo.

# C# Image Overlay

public void ApplyImageOverlay(IBaseFilter effectFilter, string imagePath)
{
    var effects = effectFilter as IVFEffects45;
    if (effects != null)
    {
        // Enable graphic logo effect
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GRAPHICLOGO, 1);

        // Set image file path
        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GRAPHICLOGO,
            "ImageFile",
            imagePath);

        // Set position (0-100% of screen)
        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GRAPHICLOGO,
            "X",
            10);  // 10% from left

        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GRAPHICLOGO,
            "Y",
            10);  // 10% from top

        // Set size (0-100% of original)
        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GRAPHICLOGO,
            "Width",
            25);  // 25% of screen width

        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GRAPHICLOGO,
            "Height",
            25);  // 25% of screen height

        // Set transparency (0-255)
        effects.SetEffectParam(
            VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GRAPHICLOGO,
            "Alpha",
            200);  // Semi-transparent
    }
}

# Example 5: Denoise Filters

Apply noise reduction for cleaner video.

# C# Denoise Examples

public enum DenoiseType
{
    CAST,
    Adaptive,
    Mosquito
}

public void ApplyDenoise(IBaseFilter effectFilter, DenoiseType type)
{
    var effects = effectFilter as IVFEffects45;
    if (effects != null)
    {
        switch (type)
        {
            case DenoiseType.CAST:
                // CAST denoise - good for general noise
                effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DENOISE_CAST, 1);
                break;

            case DenoiseType.Adaptive:
                // Adaptive denoise - adjusts based on content
                effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DENOISE_ADAPTIVE, 1);
                effects.SetEffectParam(
                    VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DENOISE_ADAPTIVE,
                    "Strength",
                    5);  // Strength 1-10
                break;

            case DenoiseType.Mosquito:
                // Mosquito denoise - reduces compression artifacts
                effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DENOISE_MOSQUITO, 1);
                effects.SetEffectParam(
                    VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DENOISE_MOSQUITO,
                    "Threshold",
                    30);  // Threshold value
                break;
        }
    }
}

# Example 6: All Available Effects

Complete list of all 35+ effects with basic configuration.

# C# All Effects Reference

public class AllEffectsExample
{
    public void DemonstrateAllEffects(IBaseFilter effectFilter)
    {
        var effects = effectFilter as IVFEffects45;
        if (effects == null) return;

        // Color Filters
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GREYSCALE, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_INVERT, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_RED_FILTER, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GREEN_FILTER, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BLUE_FILTER, 1);

        // Image Adjustment
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BRIGHTNESS, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BRIGHTNESS, "Value", 50);

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_CONTRAST, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_CONTRAST, "Value", 75);

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_SATURATION, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_SATURATION, "Value", 120);

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_HUE, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_HUE, "Value", 45);

        // Spatial Transforms
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_FLIP_HORIZONTAL, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_FLIP_VERTICAL, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_MIRROR, 1);

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_ROTATE, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_ROTATE, "Angle", 90);

        // Artistic Effects
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BLUR, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BLUR, "Radius", 5);

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_SHARPEN, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_SHARPEN, "Amount", 2);

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_EMBOSS, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_EDGE_DETECT, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_POSTERIZE, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_POSTERIZE, "Levels", 8);

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_SOLARIZE, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_SOLARIZE, "Threshold", 128);

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_MOSAIC, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_MOSAIC, "BlockSize", 10);

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_MARBLE, 1);

        // Noise Reduction
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DENOISE_CAST, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DENOISE_ADAPTIVE, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DENOISE_MOSQUITO, 1);

        // Deinterlacing
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DEINTERLACE_BLEND, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DEINTERLACE_TRIANGLE, 1);
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_DEINTERLACE_CAVT, 1);

        // Overlays
        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO, "Text", "Sample");

        effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GRAPHICLOGO, 1);
        effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GRAPHICLOGO, "ImageFile", "logo.png");

        // To disable an effect:
        // effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_GREYSCALE, 0);
    }
}

# Video Mixer Examples

# Example 7: Picture-in-Picture (PIP)

Mix two video sources with PIP layout.

# C# Picture-in-Picture

public class VideoMixerPIPExample
{
    private IFilterGraph2 filterGraph;
    private IBaseFilter mixerFilter;

    public void CreatePIP(string mainVideoPath, string pipVideoPath, IntPtr videoWindowHandle)
    {
        filterGraph = (IFilterGraph2)new FilterGraph();

        // Add main video source
        filterGraph.AddSourceFilter(mainVideoPath, "Main Source", out IBaseFilter mainSource);

        // Add PIP video source
        filterGraph.AddSourceFilter(pipVideoPath, "PIP Source", out IBaseFilter pipSource);

        // Add Video Mixer filter
        mixerFilter = FilterGraphTools.AddFilterFromClsid(
            filterGraph,
            Consts.CLSID_VFVideoMixer,
            "Video Mixer");

        // Configure mixer
        var mixer = mixerFilter as IVFVideoMixer;
        if (mixer != null)
        {
            // Set output size
            mixer.SetOutputParam("Width", 1920);
            mixer.SetOutputParam("Height", 1080);
            mixer.SetOutputParam("FrameRate", 30.0);

            // Configure main video (input 0) - fullscreen
            mixer.SetInputParam(0, "X", 0);
            mixer.SetInputParam(0, "Y", 0);
            mixer.SetInputParam(0, "Width", 1920);
            mixer.SetInputParam(0, "Height", 1080);
            mixer.SetInputParam(0, "Alpha", 255);  // Fully opaque

            // Configure PIP video (input 1) - bottom-right corner
            mixer.SetInputParam(1, "X", 1440);    // 1920 - 480 = 1440
            mixer.SetInputParam(1, "Y", 810);     // 1080 - 270 = 810
            mixer.SetInputParam(1, "Width", 480); // 25% width
            mixer.SetInputParam(1, "Height", 270); // 25% height
            mixer.SetInputParam(1, "Alpha", 255);

            // Set Z-order (layering)
            mixer.SetInputOrder(new int[] { 0, 1 }); // Main behind, PIP on top
        }

        // Connect filters
        ICaptureGraphBuilder2 captureGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
        captureGraph.SetFiltergraph(filterGraph);

        // Connect main source to mixer input 0
        captureGraph.RenderStream(null, MediaType.Video, mainSource, null, mixerFilter);

        // Connect PIP source to mixer input 1
        // Note: Requires connecting to specific input pin
        IPin mixerInput1 = DsFindPin.ByDirection(mixerFilter, PinDirection.Input, 1);
        captureGraph.RenderStream(null, MediaType.Video, pipSource, null, null);
        // Connect to mixerInput1 explicitly...

        // Render mixer output
        captureGraph.RenderStream(null, MediaType.Video, mixerFilter, null, null);

        // Setup video window
        var videoWindow = (IVideoWindow)filterGraph;
        videoWindow.put_Owner(videoWindowHandle);
        videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings);

        // Run
        var mediaControl = (IMediaControl)filterGraph;
        mediaControl.Run();

        Marshal.ReleaseComObject(captureGraph);
    }
}

# Example 8: Multi-Source Mixing (4 inputs)

Create a 2x2 grid layout with 4 video sources.

# C# 2x2 Grid Layout

public class VideoMixerGridExample
{
    public void Create2x2Grid(string[] videoPaths, IntPtr videoWindowHandle)
    {
        if (videoPaths.Length != 4)
        {
            throw new ArgumentException("Requires exactly 4 video sources");
        }

        var filterGraph = (IFilterGraph2)new FilterGraph();

        // Add all source filters
        IBaseFilter[] sources = new IBaseFilter[4];
        for (int i = 0; i < 4; i++)
        {
            filterGraph.AddSourceFilter(videoPaths[i], $"Source {i}", out sources[i]);
        }

        // Add Video Mixer
        var mixerFilter = FilterGraphTools.AddFilterFromClsid(
            filterGraph,
            Consts.CLSID_VFVideoMixer,
            "Video Mixer");

        var mixer = mixerFilter as IVFVideoMixer;
        if (mixer != null)
        {
            // Set output size
            mixer.SetOutputParam("Width", 1920);
            mixer.SetOutputParam("Height", 1080);
            mixer.SetOutputParam("FrameRate", 30.0);

            // Configure 2x2 grid layout
            int halfWidth = 960;   // 1920 / 2
            int halfHeight = 540;  // 1080 / 2

            // Top-left (Input 0)
            mixer.SetInputParam(0, "X", 0);
            mixer.SetInputParam(0, "Y", 0);
            mixer.SetInputParam(0, "Width", halfWidth);
            mixer.SetInputParam(0, "Height", halfHeight);

            // Top-right (Input 1)
            mixer.SetInputParam(1, "X", halfWidth);
            mixer.SetInputParam(1, "Y", 0);
            mixer.SetInputParam(1, "Width", halfWidth);
            mixer.SetInputParam(1, "Height", halfHeight);

            // Bottom-left (Input 2)
            mixer.SetInputParam(2, "X", 0);
            mixer.SetInputParam(2, "Y", halfHeight);
            mixer.SetInputParam(2, "Width", halfWidth);
            mixer.SetInputParam(2, "Height", halfHeight);

            // Bottom-right (Input 3)
            mixer.SetInputParam(3, "X", halfWidth);
            mixer.SetInputParam(3, "Y", halfHeight);
            mixer.SetInputParam(3, "Width", halfWidth);
            mixer.SetInputParam(3, "Height", halfHeight);

            // All inputs fully opaque
            for (int i = 0; i < 4; i++)
            {
                mixer.SetInputParam(i, "Alpha", 255);
            }

            // Set Z-order (all on same level)
            mixer.SetInputOrder(new int[] { 0, 1, 2, 3 });
        }

        // Connect sources to mixer and render...
        // (Similar to PIP example)

        var mediaControl = (IMediaControl)filterGraph;
        mediaControl.Run();
    }
}

# Example 9: Video Mixer with Chroma Key

Mix sources with transparent background.

# C# Mixer with Chroma Key

public void CreateMixerWithChromaKey(string backgroundPath, string foregroundPath)
{
    var filterGraph = (IFilterGraph2)new FilterGraph();

    // Add sources
    filterGraph.AddSourceFilter(backgroundPath, "Background", out IBaseFilter bgSource);
    filterGraph.AddSourceFilter(foregroundPath, "Foreground", out IBaseFilter fgSource);

    // Add mixer
    var mixerFilter = FilterGraphTools.AddFilterFromClsid(
        filterGraph,
        Consts.CLSID_VFVideoMixer,
        "Video Mixer");

    var mixer = mixerFilter as IVFVideoMixer;
    if (mixer != null)
    {
        // Configure output
        mixer.SetOutputParam("Width", 1920);
        mixer.SetOutputParam("Height", 1080);

        // Background (fullscreen)
        mixer.SetInputParam(0, "X", 0);
        mixer.SetInputParam(0, "Y", 0);
        mixer.SetInputParam(0, "Width", 1920);
        mixer.SetInputParam(0, "Height", 1080);

        // Foreground (centered, smaller)
        mixer.SetInputParam(1, "X", 480);
        mixer.SetInputParam(1, "Y", 270);
        mixer.SetInputParam(1, "Width", 960);
        mixer.SetInputParam(1, "Height", 540);

        // Enable chroma key for foreground input
        mixer.SetChromaSettings(
            inputIndex: 1,
            enabled: true,
            colorR: 0,      // Green screen
            colorG: 255,
            colorB: 0,
            threshold: 50,  // Tolerance
            blend: 10);     // Edge smoothing
    }

    // Connect and run...
}

# Chroma Key Examples

# Example 10: Green Screen Effect

Standalone chroma key filter for green screen removal.

# C# Chroma Key Filter

public class ChromaKeyExample
{
    public void ApplyGreenScreen(string videoPath, string backgroundImagePath, IntPtr videoWindowHandle)
    {
        var filterGraph = (IFilterGraph2)new FilterGraph();

        // Add video source (with green screen)
        filterGraph.AddSourceFilter(videoPath, "Source", out IBaseFilter sourceFilter);

        // Add Chroma Key filter
        var chromaFilter = FilterGraphTools.AddFilterFromClsid(
            filterGraph,
            Consts.CLSID_VFChromaKey,
            "Chroma Key");

        // Configure chroma key
        var chromaKey = chromaFilter as IVFChromaKey;
        if (chromaKey != null)
        {
            // Set key color (green)
            chromaKey.chroma_put_color(
                red: 0,
                green: 255,
                blue: 0);

            // Set contrast/threshold
            chromaKey.chroma_put_contrast(
                contrast1: 50,  // Lower threshold
                contrast2: 100); // Upper threshold

            // Set background image (optional)
            if (!string.IsNullOrEmpty(backgroundImagePath))
            {
                chromaKey.chroma_put_image(backgroundImagePath);
            }
        }

        // Connect filters: Source → Chroma Key → Renderer
        ICaptureGraphBuilder2 captureGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
        captureGraph.SetFiltergraph(filterGraph);

        captureGraph.RenderStream(null, MediaType.Video, sourceFilter, chromaFilter, null);
        captureGraph.RenderStream(null, MediaType.Audio, sourceFilter, null, null);

        // Setup video window
        var videoWindow = (IVideoWindow)filterGraph;
        videoWindow.put_Owner(videoWindowHandle);
        videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings);

        // Run
        var mediaControl = (IMediaControl)filterGraph;
        mediaControl.Run();

        Marshal.ReleaseComObject(captureGraph);
    }
}

# C++ Chroma Key

HRESULT ApplyChromaKey(IBaseFilter* pChromaFilter)
{
    IVFChromaKey* pChromaKey = NULL;

    HRESULT hr = pChromaFilter->QueryInterface(IID_IVFChromaKey, (void**)&pChromaKey);
    if (FAILED(hr)) return hr;

    // Set green color (RGB)
    hr = pChromaKey->chroma_put_color(0, 255, 0);
    if (FAILED(hr)) goto cleanup;

    // Set thresholds
    hr = pChromaKey->chroma_put_contrast(40, 90);
    if (FAILED(hr)) goto cleanup;

    // Optional: Set background image
    hr = pChromaKey->chroma_put_image(L"C:\\backgrounds\\studio.jpg");

cleanup:
    pChromaKey->Release();
    return hr;
}

# Example 11: Blue Screen with Fine Tuning

Configure blue screen chroma key with optimal settings.

# C# Blue Screen

public void ApplyBlueScreen(IBaseFilter chromaFilter)
{
    var chromaKey = chromaFilter as IVFChromaKey;
    if (chromaKey != null)
    {
        // Set blue color
        chromaKey.chroma_put_color(
            red: 0,
            green: 0,
            blue: 255);

        // Fine-tuned thresholds for blue screen
        // Lower values = more strict (less tolerance)
        // Higher values = more loose (more tolerance)
        chromaKey.chroma_put_contrast(
            contrast1: 30,   // Tighter lower threshold
            contrast2: 80);  // Moderate upper threshold
    }
}

# Example 12: Custom Color Chroma Key

Use any custom color for keying.

# C# Custom Color Key

public void ApplyCustomColorKey(IBaseFilter chromaFilter, Color keyColor)
{
    var chromaKey = chromaFilter as IVFChromaKey;
    if (chromaKey != null)
    {
        // Use any custom color
        chromaKey.chroma_put_color(
            red: keyColor.R,
            green: keyColor.G,
            blue: keyColor.B);

        // Standard thresholds
        chromaKey.chroma_put_contrast(50, 100);
    }
}

// Example usage:
// ApplyCustomColorKey(chromaFilter, Color.Magenta);  // Magenta screen
// ApplyCustomColorKey(chromaFilter, Color.FromArgb(255, 180, 0, 220));  // Custom purple

# Complete Processing Pipeline

# Example 13: Combined Effects, Mixing, and Chroma Key

Complete example combining all processing filters.

# C# Complete Pipeline

public class CompleteProcessingPipeline
{
    public void CreateCompleteSetup(
        string mainVideoPath,
        string greenScreenVideoPath,
        string backgroundImagePath,
        IntPtr videoWindowHandle)
    {
        var filterGraph = (IFilterGraph2)new FilterGraph();

        // 1. Main video source
        filterGraph.AddSourceFilter(mainVideoPath, "Main Video", out IBaseFilter mainSource);

        // 2. Green screen video source
        filterGraph.AddSourceFilter(greenScreenVideoPath, "Green Screen", out IBaseFilter gsSource);

        // 3. Add Chroma Key filter for green screen
        var chromaFilter = FilterGraphTools.AddFilterFromClsid(
            filterGraph,
            Consts.CLSID_VFChromaKey,
            "Chroma Key");

        var chromaKey = chromaFilter as IVFChromaKey;
        if (chromaKey != null)
        {
            chromaKey.chroma_put_color(0, 255, 0);  // Green
            chromaKey.chroma_put_contrast(40, 90);
        }

        // 4. Add Video Effects filter
        var effectsFilter = FilterGraphTools.AddFilterFromClsid(
            filterGraph,
            Consts.CLSID_VFVideoEffects,
            "Video Effects");

        var effects = effectsFilter as IVFEffects45;
        if (effects != null)
        {
            // Apply some effects
            effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BRIGHTNESS, 1);
            effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BRIGHTNESS, "Value", 60);

            effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_CONTRAST, 1);
            effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_CONTRAST, "Value", 80);

            // Add text overlay
            effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO, 1);
            effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO, "Text", "LIVE");
            effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO, "FontSize", 48);
            effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO, "X", 50);
            effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_TEXTLOGO, "Y", 50);
        }

        // 5. Add Video Mixer
        var mixerFilter = FilterGraphTools.AddFilterFromClsid(
            filterGraph,
            Consts.CLSID_VFVideoMixer,
            "Video Mixer");

        var mixer = mixerFilter as IVFVideoMixer;
        if (mixer != null)
        {
            mixer.SetOutputParam("Width", 1920);
            mixer.SetOutputParam("Height", 1080);
            mixer.SetOutputParam("FrameRate", 30.0);

            // Main video (fullscreen background)
            mixer.SetInputParam(0, "X", 0);
            mixer.SetInputParam(0, "Y", 0);
            mixer.SetInputParam(0, "Width", 1920);
            mixer.SetInputParam(0, "Height", 1080);

            // Chroma-keyed video (PIP)
            mixer.SetInputParam(1, "X", 1200);
            mixer.SetInputParam(1, "Y", 700);
            mixer.SetInputParam(1, "Width", 640);
            mixer.SetInputParam(1, "Height", 360);

            mixer.SetInputOrder(new int[] { 0, 1 });
        }

        // Connect the pipeline:
        // Main Source → Effects → Mixer Input 0
        // GS Source → Chroma Key → Mixer Input 1
        // Mixer → Renderer

        ICaptureGraphBuilder2 captureGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
        captureGraph.SetFiltergraph(filterGraph);

        // Connect main path
        captureGraph.RenderStream(null, MediaType.Video, mainSource, effectsFilter, mixerFilter);

        // Connect chroma key path
        // (Requires pin-level connections to specific mixer input)

        // Render mixer output
        captureGraph.RenderStream(null, MediaType.Video, mixerFilter, null, null);

        // Audio
        captureGraph.RenderStream(null, MediaType.Audio, mainSource, null, null);

        // Setup video window
        var videoWindow = (IVideoWindow)filterGraph;
        videoWindow.put_Owner(videoWindowHandle);
        videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings);

        // Run
        var mediaControl = (IMediaControl)filterGraph;
        mediaControl.Run();

        Marshal.ReleaseComObject(captureGraph);
    }
}

# Troubleshooting

# Issue: Effect Not Visible

Solution: Ensure effect is enabled and parameters are set:

effects.SetEffect(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BRIGHTNESS, 1);  // 1 = enabled
effects.SetEffectParam(VF_VIDEO_EFFECT.VF_VIDEO_EFFECT_BRIGHTNESS, "Value", 75);

# Issue: Chroma Key Not Working Well

Solution: Adjust contrast thresholds:

// For difficult green screens:
chromaKey.chroma_put_contrast(30, 70);  // Tighter range

// For well-lit green screens:
chromaKey.chroma_put_contrast(50, 110);  // Wider range

# Issue: Video Mixer Inputs Not Showing

Solution: Verify input parameters and Z-order:

// Ensure inputs are on-screen
mixer.SetInputParam(index, "X", 0);     // Must be >= 0
mixer.SetInputParam(index, "Y", 0);     // Must be >= 0
mixer.SetInputParam(index, "Width", 640);  // Must be > 0
mixer.SetInputParam(index, "Height", 480); // Must be > 0

// Check Z-order
mixer.SetInputOrder(new int[] { 0, 1, 2 });  // 0 = back, 2 = front

# See Also

# Documentation

# External Resources