npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

gst-kit

v0.2.2

Published

Node.js binding for GStreamer, providing high-level APIs for multimedia streaming and processing

Readme

GStreamer Kit

A modern Node.js binding for GStreamer, providing high-level APIs for multimedia streaming and processing. This project modernizes the legacy node-gstreamer-superficial library with contemporary technologies and improved runtime support.

Project Goals & Modernization

This project represents a complete modernization of the old node-gstreamer-superficial library, featuring:

Modern Runtime Support

  • N-API instead of NAN: Uses Node-API (N-API) for better runtime stability and version independence
  • Multi-runtime compatibility: Supports Node.js 16+, Bun 1.0+, and other V8-based runtimes
  • Version independence: Not bound to specific V8 versions, ensuring longevity

Modern Build System

  • Rollup bundling: Generates both CommonJS and ESM modules for maximum compatibility
  • TypeScript-first: Complete TypeScript support with full type definitions
  • GYP build system: Robust C++ compilation with proper dependency management
  • Modern testing: Uses Vitest for fast, concurrent testing instead of legacy test frameworks

Enhanced Developer Experience

  • Full TypeScript support: Complete type definitions for all APIs
  • ESM/CJS dual packaging: Works with both import and require statements
  • Comprehensive testing: Extensive test coverage with modern test runner
  • Better documentation: Clear examples and API documentation

Complete Feature Set

Core Pipeline Features

  • Pipeline Management: Create, play, pause, stop GStreamer pipelines
  • State Management: Comprehensive state change handling with detailed results
  • Element Access: Get elements by name with proper typing
  • Property System: Get/set element properties with type safety

Advanced Data Access

  • App Sources & Sinks: Two approaches for data access:
    • Pull-based: Explicitly request samples with getSample() (async, controlled timing)
    • Push-based: Reactive callbacks with onSample() (automatic, real-time)
  • Pad Probes: Add/remove event-driven callbacks to intercept comprehensive buffer data
  • Buffer Analysis: Extract raw data, timing information, flags, caps, and metadata

Media Processing

  • RTP Support: Extract RTP metadata including timestamps, sequence numbers, SSRC, payload type
  • Seeking: Frame-accurate seeking with success feedback
  • Query System: Position and duration queries in seconds
  • Message Bus: Handle GStreamer messages (EOS, errors, warnings, state changes)

Runtime Features

  • Multi-format Support: Video, audio, containers, streaming protocols
  • Codec Support: H.264, H.265, VP8, VP9, AV1, and more through GStreamer plugins
  • Network Streaming: RTP, RTSP, HLS, DASH, WebRTC protocols
  • Hardware Acceleration: GPU-accelerated encoding/decoding where available

Installation

npm install gst-kit

System Requirements

  • Runtime: Node.js 16+ or Bun 1.0+ (Deno is not supported)
  • System: GStreamer 1.14 or higher (1.26+ recommended)
  • Build Tools: Python 2.7 or 3.x (for node-gyp), pkg-config
  • Dependencies: GStreamer development packages and plugins

Platform-Specific Installation Guide

Cross-Platform Alternative: For any operating system, you can use the setup-cpp tool to automatically install compilers, build tools, and package managers:

# Install development tools across platforms (Windows, macOS, Linux)
npx setup-cpp --compiler auto --pkg-config true

# On Windows, this can also install Chocolatey:
npx setup-cpp --compiler msvc --pkg-config true --choco true

Ubuntu/Debian (Recommended for Production)

Option A: Package Manager (Traditional)
# Update package list
sudo apt-get update

# Install GStreamer core development packages
sudo apt-get install -y \
  libgstreamer1.0-dev \
  libgstreamer-plugins-base1.0-dev \
  libgstreamer-plugins-bad1.0-dev \
  pkg-config

# Install GStreamer plugins (essential for most use cases)
sudo apt-get install -y \
  gstreamer1.0-plugins-base \
  gstreamer1.0-plugins-good \
  gstreamer1.0-plugins-bad \
  gstreamer1.0-plugins-ugly \
  gstreamer1.0-libav

# Install build tools
sudo apt-get install -y build-essential python3
Option B: Cross-Platform Setup with setup-cpp (Ubuntu)
# Install build tools automatically
npx setup-cpp --compiler auto --pkg-config true

# Then install GStreamer packages
sudo apt-get update
sudo apt-get install -y \
  libgstreamer1.0-dev \
  libgstreamer-plugins-base1.0-dev \
  libgstreamer-plugins-bad1.0-dev \
  gstreamer1.0-plugins-base \
  gstreamer1.0-plugins-good \
  gstreamer1.0-plugins-bad \
  gstreamer1.0-plugins-ugly \
  gstreamer1.0-libav

Verification:

pkg-config --cflags --libs gstreamer-1.0
gst-launch-1.0 --version

macOS (Homebrew)

Option A: Homebrew (Traditional)
# Install GStreamer and plugins
brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly pkg-config

# Set environment variables (add to ~/.zshrc or ~/.bash_profile)
export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig:$PKG_CONFIG_PATH"
export LIBRARY_PATH="$(brew --prefix)/lib:$LIBRARY_PATH"
export LD_LIBRARY_PATH="$(brew --prefix)/lib:$LD_LIBRARY_PATH"
Option B: Cross-Platform Setup with setup-cpp (macOS)
# Install build tools automatically
npx setup-cpp --compiler auto --pkg-config true

# Then install GStreamer via Homebrew
brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly

# Set environment variables (add to ~/.zshrc or ~/.bash_profile)
export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig:$PKG_CONFIG_PATH"
export LIBRARY_PATH="$(brew --prefix)/lib:$LIBRARY_PATH"
export LD_LIBRARY_PATH="$(brew --prefix)/lib:$LD_LIBRARY_PATH"

Verification:

pkg-config --cflags --libs gstreamer-1.0
gst-launch-1.0 --version

Windows

Complete Installation:

  1. Install Build Tools:

    Option A: Manual Installation
    # Install Visual Studio Build Tools 2019/2022 (Community edition is free)
    # Download from: https://visualstudio.microsoft.com/downloads/
    
    # Install pkg-config (REQUIRED for build to work)
    choco install pkgconfiglite
    Option B: Cross-Platform Setup with setup-cpp (Recommended)
    # Use setup-cpp for automated toolchain installation (works on Windows, macOS, Linux)
    # This tool can install compilers, package managers (including Chocolatey), and build systems
    npx setup-cpp --compiler msvc --pkg-config true --choco true
  2. Install GStreamer 1.26.2:

    # Download both runtime and development MSI packages from:
    # https://gstreamer.freedesktop.org/download/
    
    # For 64-bit systems, download and install:
    # - gstreamer-1.0-msvc-x86_64-1.26.2.msi (runtime)
    # - gstreamer-1.0-devel-msvc-x86_64-1.26.2.msi (development)
    
    # Install both MSI files by double-clicking or using:
    # msiexec /i gstreamer-1.0-msvc-x86_64-1.26.2.msi /quiet
    # msiexec /i gstreamer-1.0-devel-msvc-x86_64-1.26.2.msi /quiet
  3. Set Environment Variables:

    # Add to system PATH (via System Properties → Environment Variables):
    C:\Program Files\gstreamer\1.0\msvc_x86_64\bin
    
    # Add system environment variables:
    GSTREAMER_1_0_ROOT_MSVC_X86_64=C:\Program Files\gstreamer\1.0\msvc_x86_64
    PKG_CONFIG_PATH=C:\Program Files\gstreamer\1.0\msvc_x86_64\lib\pkgconfig

Verification:

# Verify pkg-config can find GStreamer (most important for building)
pkg-config --exists gstreamer-1.0; if ($LASTEXITCODE -eq 0) { Write-Host "GStreamer found" } else { Write-Host "GStreamer NOT found" }
pkg-config --cflags --libs gstreamer-1.0

Windows-Specific Troubleshooting:

If you encounter build errors after installation, try these common fixes:

  1. PKG_CONFIG_PATH Issues:

    # If GStreamer was installed to default location but pkg-config can't find it:
    setx PKG_CONFIG_PATH "C:\Program Files\gstreamer\1.0\msvc_x86_64\lib\pkgconfig"
    
    # Restart your terminal/command prompt after setting this variable
    # Verify the fix:
    pkg-config --exists gstreamer-1.0; if ($LASTEXITCODE -eq 0) { Write-Host "GStreamer found" } else { Write-Host "GStreamer NOT found" }
  2. Missing pkg-config:

    # pkg-config is absolutely required - install if missing:
    choco install pkgconfiglite
    
    # Or refresh your PATH if already installed:
    refreshenv
  3. GStreamer Location Mismatch:

    # If GStreamer was installed to a different location, update PKG_CONFIG_PATH accordingly:
    # For example, if installed to C:\gstreamer:
    setx PKG_CONFIG_PATH "C:\gstreamer\1.0\msvc_x86_64\lib\pkgconfig"

Common Installation Issues

Problem: "Cannot find gstreamer-1.0"

Solution:

# Ubuntu/Debian
sudo apt-get install libgstreamer1.0-dev pkg-config

# macOS
brew install gstreamer pkg-config
export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig:$PKG_CONFIG_PATH"

# Windows (PowerShell)
# Ensure pkg-config is installed:
choco install pkgconfiglite

# Ensure environment variables are set correctly:
# GSTREAMER_1_0_ROOT_MSVC_X86_64=C:\Program Files\gstreamer\1.0\msvc_x86_64
# PKG_CONFIG_PATH=C:\Program Files\gstreamer\1.0\msvc_x86_64\lib\pkgconfig

# If GStreamer is installed but pkg-config can't find it, set PKG_CONFIG_PATH:
setx PKG_CONFIG_PATH "C:\Program Files\gstreamer\1.0\msvc_x86_64\lib\pkgconfig"

# Verify pkg-config can find GStreamer
pkg-config --exists gstreamer-1.0; if ($LASTEXITCODE -eq 0) { Write-Host "GStreamer found" } else { Write-Host "GStreamer NOT found" }

Problem: Missing plugins (playbin/decodebin errors)

Solution:

# Ubuntu/Debian - install plugin packages
sudo apt-get install gstreamer1.0-plugins-{base,good,bad,ugly} gstreamer1.0-libav

# macOS - install plugin packages
brew install gst-plugins-{base,good,bad,ugly}

# List available plugins
gst-inspect-1.0 | grep -i plugin

Problem: "Permission denied" on Linux

Solution:

# Add user to audio/video groups
sudo usermod -a -G audio,video $USER
# Logout and login again

# Or install PulseAudio for audio support
sudo apt-get install pulseaudio pulseaudio-utils

Docker Installation

For containerized applications:

# Ubuntu-based container
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y \
    nodejs npm \
    libgstreamer1.0-dev \
    libgstreamer-plugins-base1.0-dev \
    libgstreamer-plugins-bad1.0-dev \
    gstreamer1.0-plugins-base \
    gstreamer1.0-plugins-good \
    gstreamer1.0-plugins-bad \
    gstreamer1.0-plugins-ugly \
    gstreamer1.0-libav \
    build-essential pkg-config python3 \
    && rm -rf /var/lib/apt/lists/*

# Install your application
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

Quick Start

Basic Pipeline

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline("videotestsrc ! autovideosink");
await pipeline.play();

// Stop after 5 seconds
setTimeout(async () => {
  await pipeline.stop();
}, 5000);

Checking Element Availability

import { Pipeline } from "gst-kit";

// Check if specific GStreamer elements are available before using them
if (Pipeline.elementExists("x264enc")) {
  console.log("H.264 encoder is available");
  const pipeline = new Pipeline("videotestsrc ! x264enc ! mp4mux ! filesink location=output.mp4");
} else {
  console.log("x264enc not found, using alternative encoder");
  const pipeline = new Pipeline("videotestsrc ! vp8enc ! webmmux ! filesink location=output.webm");
}

// Check hardware acceleration support
const hasVaapi = Pipeline.elementExists("vaapih264enc");
const hasNvenc = Pipeline.elementExists("nvh264enc");
console.log(`VAAPI support: ${hasVaapi}, NVENC support: ${hasNvenc}`);

Working with AppSink (Pull-based Approach)

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline("videotestsrc num-buffers=10 ! videoconvert ! appsink name=sink");
const sink = pipeline.getElementByName("sink");

if (sink?.type === "app-sink-element") {
  await pipeline.play();

  while (true) {
    const sample = await sink.getSample(); // Explicitly request samples
    if (!sample) break;

    console.log("Received frame:", sample.buffer?.length, "bytes");
  }

  await pipeline.stop();
}

Working with AppSink (Event-Driven/Push Approach)

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline("videotestsrc num-buffers=10 ! videoconvert ! appsink name=sink");
const sink = pipeline.getElementByName("sink");

if (sink?.type === "app-sink-element") {
  let frameCount = 0;

  // Set up reactive callback - samples are pushed automatically
  const unsubscribe = sink.onSample(sample => {
    frameCount++;
    console.log(`Frame ${frameCount}:`, sample.buffer?.length, "bytes");

    if (frameCount === 10) {
      unsubscribe();
      pipeline.stop();
    }
  });

  await pipeline.play();
}

Working with AppSrc (Source Input)

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline("appsrc name=source ! videoconvert ! autovideosink");
const source = pipeline.getElementByName("source");

if (source?.type === "app-src-element") {
  source.setElementProperty("caps", "video/x-raw,format=RGB,width=320,height=240");
  source.setElementProperty("is-live", true);

  await pipeline.play();

  // Push random RGB frames
  setInterval(() => {
    const buffer = Buffer.alloc(320 * 240 * 3);
    buffer.fill(Math.floor(Math.random() * 255));
    source.push(buffer);
  }, 33); // ~30 FPS
}

Working with AppSrc for Custom Data Sources (with EOS)

Use AppSrc with EOS when you need to process data that can't be handled by standard GStreamer elements like filesrc:

import { Pipeline } from "gst-kit";
import { createReadStream } from "fs";

// Real-world scenarios where AppSrc + EOS is needed:
// 1. Custom encrypted file formats
// 2. Network streams with custom protocols
// 3. Database BLOBs containing media data
// 4. Programmatically generated content with known duration
// 5. Multi-source aggregation

async function streamEncryptedVideoFile(encryptedFilePath) {
  const pipeline = new Pipeline("appsrc name=source ! h264parse ! avdec_h264 ! autovideosink");
  const source = pipeline.getElementByName("source");

  if (source?.type === "app-src-element") {
    source.setElementProperty("caps", "video/x-h264,stream-format=byte-stream");
    source.setElementProperty("is-live", false); // File-like behavior

    await pipeline.play();

    // Read and decrypt file chunks
    const encryptedStream = createReadStream(encryptedFilePath);

    for await (const encryptedChunk of encryptedStream) {
      // Decrypt the chunk (your custom decryption logic)
      const decryptedBuffer = await decryptChunk(encryptedChunk);
      source.push(decryptedBuffer);
    }

    // IMPORTANT: Signal end-of-stream when file is fully processed
    source.endOfStream();

    // Wait for natural completion
    while (true) {
      const message = await pipeline.busPop(1000);
      if (message?.type === "eos") {
        console.log("Encrypted file playback completed");
        break;
      }
    }

    await pipeline.stop();
  }
}

// Example: Stream from database BLOB
async function streamFromDatabase(mediaId) {
  const pipeline = new Pipeline("appsrc name=source ! decodebin ! autovideosink");
  const source = pipeline.getElementByName("source");

  if (source?.type === "app-src-element") {
    // Note: Let decodebin auto-detect format
    source.setElementProperty("is-live", false);

    await pipeline.play();

    // Stream media data from database in chunks
    const mediaChunks = await fetchMediaFromDatabase(mediaId);

    for (const chunk of mediaChunks) {
      source.push(chunk);
    }

    source.endOfStream(); // Signal completion

    // Handle completion
    while (true) {
      const message = await pipeline.busPop(1000);
      if (message?.type === "eos") break;
    }

    await pipeline.stop();
  }
}

// Placeholder functions - implement according to your needs
async function decryptChunk(encryptedData) {
  // Your decryption logic here
  return encryptedData; // Return decrypted buffer
}

async function fetchMediaFromDatabase(mediaId) {
  // Your database fetch logic here
  return []; // Return array of media chunks
}

Recording Programmatically Generated Streams to Files

For recording programmatically generated content (procedural video, custom visualizations, etc.) to video files:

import { Pipeline } from "gst-kit";
import path from "path";
import fs from "fs";

async function recordGeneratedVideoToFile() {
  const outputFile = path.join(process.cwd(), "recording.ogv");

  // Remove existing file if it exists
  if (fs.existsSync(outputFile)) {
    fs.unlinkSync(outputFile);
  }

  // Create recording pipeline (OGV/Theora is most reliable for programmatic content)
  const pipeline = new Pipeline(`
    appsrc name=mysource ! 
    videoconvert ! 
    theoraenc ! 
    oggmux ! 
    filesink location=${outputFile}
  `);

  const appsrc = pipeline.getElementByName("mysource");

  if (appsrc?.type === "app-src-element") {
    // Configure for file recording (not live streaming)
    appsrc.setElementProperty("caps", "video/x-raw,format=RGB,width=640,height=480,framerate=30/1");
    appsrc.setElementProperty("format", "time");
    appsrc.setElementProperty("is-live", false);
    appsrc.setElementProperty("do-timestamp", true);

    await pipeline.play();

    // Generate and push frames
    const frameCount = 300; // 10 seconds at 30fps
    const width = 640;
    const height = 480;
    const frameSize = width * height * 3; // RGB

    for (let i = 0; i < frameCount; i++) {
      // Generate frame data (replace with your content generation logic)
      const buffer = generateFrame(i, width, height);
      appsrc.push(buffer);

      if (i % 30 === 0) {
        console.log(`📹 Recorded ${i} frames (${i / 30} seconds)`);
      }
    }

    // CRITICAL: Signal end-of-stream when done generating content
    appsrc.endOfStream();

    // Wait for recording completion
    while (true) {
      const message = await pipeline.busPop(1000);
      if (!message) continue;

      if (message.type === "eos") {
        console.log("🎉 Recording completed!");
        break;
      } else if (message.type === "error") {
        console.error("❌ Recording error:", message.message);
        break;
      }
    }

    await pipeline.stop();

    // Verify file was created
    if (fs.existsSync(outputFile)) {
      const stats = fs.statSync(outputFile);
      console.log(`✅ File size: ${(stats.size / 1024 / 1024).toFixed(2)} MB`);
    }
  }
}

function generateFrame(frameNumber, width, height) {
  // Example: Generate animated colored frames
  const buffer = Buffer.alloc(width * height * 3);
  const red = (frameNumber * 5) % 256;
  const green = (frameNumber * 3) % 256;
  const blue = (frameNumber * 7) % 256;

  for (let i = 0; i < buffer.length; i += 3) {
    buffer[i] = red; // R
    buffer[i + 1] = green; // G
    buffer[i + 2] = blue; // B
  }

  return buffer;
}

// Usage
recordGeneratedVideoToFile();

Key Points for File Recording:

  • EOS is Required: Always call endOfStream() when done pushing data
  • OGV/Theora: Most reliable format for programmatic content
  • Non-live Mode: Set is-live: false for file-like behavior
  • Timestamping: Enable do-timestamp: true for proper timing
  • Error Handling: Monitor bus messages for completion and errors

Extracting Buffer Data with Pad Probes

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline(
  "videotestsrc ! videoconvert ! x264enc ! rtph264pay name=pay ! fakesink"
);
const payloader = pipeline.getElementByName("pay");

if (payloader) {
  // Add probe to capture comprehensive buffer data from pad
  const unsubscribe = payloader.addPadProbe("src", bufferData => {
    console.log("Buffer Data:", {
      // Raw buffer data
      buffer: bufferData.buffer, // Buffer object with raw data
      size: bufferData.buffer?.length, // Buffer size in bytes

      // Timing information (nanoseconds)
      pts: bufferData.pts, // Presentation timestamp
      dts: bufferData.dts, // Decode timestamp
      duration: bufferData.duration,
      offset: bufferData.offset,
      offsetEnd: bufferData.offsetEnd,

      // Buffer metadata
      flags: bufferData.flags, // GStreamer buffer flags

      // Stream format information
      caps: bufferData.caps, // Caps object with format details

      // RTP data (only for RTP streams)
      rtp: bufferData.rtp
        ? {
            timestamp: bufferData.rtp.timestamp,
            sequence: bufferData.rtp.sequence,
            ssrc: bufferData.rtp.ssrc,
            payloadType: bufferData.rtp.payloadType,
          }
        : undefined,
    });
  });

  await pipeline.play();

  // ... later, remove the probe
  unsubscribe();
  await pipeline.stop();
}

Pipeline State Management

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline("videotestsrc ! autovideosink");

// State change operations return detailed results
const playResult = await pipeline.play();
console.log("Play result:", playResult.result); // 'success', 'async', 'failure', etc.
console.log("Current state:", playResult.finalState);

// Check if pipeline is playing
console.log("Is playing:", pipeline.playing());

// Pause and resume
await pipeline.pause();
await pipeline.play();

// Stop pipeline
await pipeline.stop();

Position and Duration Queries

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline("videotestsrc ! timeoverlay ! autovideosink");
await pipeline.play();

setInterval(() => {
  const position = pipeline.queryPosition(); // Position in seconds
  const duration = pipeline.queryDuration(); // Duration in seconds
  console.log(`Position: ${position}s / Duration: ${duration}s`);
}, 1000);

Seeking

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline("videotestsrc ! timeoverlay ! autovideosink");
await pipeline.play();

// Seek to 60 seconds
const seekSuccess = pipeline.seek(60);
console.log("Seek successful:", seekSuccess);

Message Bus Handling

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline("videotestsrc num-buffers=100 ! autovideosink");
await pipeline.play();

// Listen for bus messages
while (true) {
  const message = await pipeline.busPop(1000); // 1 second timeout

  if (message) {
    console.log("Message:", message.type, message.srcElementName);

    if (message.type === "eos") {
      console.log("End of stream");
      break;
    } else if (message.type === "error") {
      console.error("Error:", message.errorMessage);
      break;
    }
  }
}

Element Property Manipulation

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline("videotestsrc name=source ! capsfilter name=filter ! autovideosink");

const source = pipeline.getElementByName("source");
const filter = pipeline.getElementByName("filter");

// Set various property types
source?.setElementProperty("pattern", "ball");
source?.setElementProperty("is-live", true);
source?.setElementProperty("num-buffers", 100);

filter?.setElementProperty("caps", "video/x-raw,width=1280,height=720,framerate=30/1");

// Get property values
const patternResult = source?.getElementProperty("pattern");
const capsResult = filter?.getElementProperty("caps");

// Access the actual values using the standardized format
const pattern = patternResult?.value;
const caps = capsResult?.value;

Pad Manipulation

import { Pipeline } from "gst-kit";

const pipeline = new Pipeline(
  "input-selector name=sel ! autovideosink videotestsrc pattern=0 ! sel.sink_0 videotestsrc pattern=1 ! sel.sink_1"
);

const selector = pipeline.getElementByName("sel");
await pipeline.play();

// Switch between input pads
setInterval(() => {
  const activePad = Math.random() > 0.5 ? "sink_0" : "sink_1";
  selector?.setPad("active-pad", activePad);
  console.log("Switched to:", activePad);
}, 2000);

// Get pad information
const srcPad = selector?.getPad("src");
console.log("Pad info:", srcPad?.name, srcPad?.direction, srcPad?.caps);

API Reference

Pipeline Class

class Pipeline {
  constructor(description: string);

  // Static methods
  static elementExists(elementName: string): boolean;

  // State management
  play(timeoutMs?: number): Promise<StateChangeResult>;
  pause(timeoutMs?: number): Promise<StateChangeResult>;
  stop(timeoutMs?: number): Promise<StateChangeResult>;
  playing(): boolean;

  // Element access
  getElementByName(name: string): Element | AppSinkElement | AppSrcElement | null;

  // Position and seeking
  queryPosition(): number;
  queryDuration(): number;
  seek(positionSeconds: number): boolean;

  // Message handling
  busPop(timeoutMs?: number): Promise<GstMessage | null>;
}

Element Types

// Base element with common functionality
interface Element {
  readonly type: "element";
  getElementProperty(key: string): GStreamerPropertyResult;
  setElementProperty(key: string, value: GStreamerPropertyValue): void;
  addPadProbe(padName: string, callback: (bufferData: BufferData) => void): () => void;
  setPad(attribute: string, padName: string): void;
  getPad(padName: string): GstPad | null;
}

// AppSink element for receiving data
interface AppSinkElement extends Element {
  readonly type: "app-sink-element";
  getSample(timeoutMs?: number): Promise<GStreamerSample | null>;
  onSample(callback: (sample: GStreamerSample) => void): () => void;
}

// AppSrc element for providing data
interface AppSrcElement extends Element {
  readonly type: "app-src-element";
  push(buffer: Buffer, pts?: Buffer | number): void;
  endOfStream(): void;
}

Buffer Flags Reference

import { GstBufferFlags } from "gst-kit";

// Check buffer flags
if (bufferData.flags & GstBufferFlags.GST_BUFFER_FLAG_DELTA_UNIT) {
  console.log("This is a delta frame (not a keyframe)");
}

if (bufferData.flags & GstBufferFlags.GST_BUFFER_FLAG_HEADER) {
  console.log("This buffer contains header data");
}

Available flags include:

  • GST_BUFFER_FLAG_LIVE: Buffer from live source
  • GST_BUFFER_FLAG_DECODE_ONLY: Buffer should only be decoded, not displayed
  • GST_BUFFER_FLAG_DISCONT: Buffer represents discontinuity
  • GST_BUFFER_FLAG_DELTA_UNIT: Buffer is delta unit (not keyframe)
  • GST_BUFFER_FLAG_HEADER: Buffer contains header information
  • And more...

Property System

Standardized Property Results

The getElementProperty() method returns a standardized object with type information:

// Property result format
const result = element.getElementProperty("property-name");

if (result === null) {
  console.log("Property value is null");
} else {
  console.log("Property type:", result.type); // "primitive" | "array" | "object" | "buffer" | "sample"
  console.log("Property value:", result.value); // The actual value
}

Property Types

  • primitive: strings, numbers, booleans, bigint (typically uint64s used to store nanoseconds)
  • array: Arrays of primitive values (strings, numbers, booleans, bigints)
  • object: GStreamer structures (like stats)
  • buffer: Raw binary data
  • sample: Media samples with buffer, caps, and metadata

Usage Examples

// String property
const patternResult = videotestsrc.getElementProperty("pattern");
if (patternResult?.type === "primitive") {
  console.log("Pattern:", patternResult.value); // e.g., "ball"
}

// Boolean property
const isLiveResult = videotestsrc.getElementProperty("is-live");
if (isLiveResult?.type === "primitive") {
  console.log("Is live:", isLiveResult.value); // true/false
}

// Structure/Object property (like stats)
const statsResult = rtpdepay.getElementProperty("stats");
if (statsResult?.type === "object") {
  const stats = statsResult.value;
  console.log("RTP timestamp:", stats.timestamp);
}

// Sample property
const sampleResult = fakesink.getElementProperty("last-sample");
if (sampleResult?.type === "sample") {
  const sample = sampleResult.value;
  console.log("Buffer size:", sample.buffer.length);
  console.log("Caps:", sample.caps);
}

Build System & Tools

Native Code (C++)

  • GYP: Cross-platform build configuration system
  • N-API: Node-API for runtime-independent native bindings
  • GStreamer Integration: Full integration with GStreamer 1.0 ecosystem
  • Compiler Support: GCC, Clang, MSVC with C++20 standard

TypeScript/JavaScript

  • Rollup: Module bundler generating both ESM and CJS outputs
  • TypeScript: Full type definitions and compilation
  • Dual Packaging: Supports both import and require statements
  • Source Maps: Full debugging support

Testing & Quality

  • Vitest: Modern, fast test runner with concurrent execution
  • ESLint: Code linting with TypeScript support
  • Prettier: Code formatting
  • Coverage: Built-in test coverage reporting

Project Structure

gst-kit/
├── src/
│   ├── cpp/                   # C++ native implementation
│   │   ├── addon.cpp          # N-API module entry point
│   │   ├── pipeline.cpp       # Pipeline class implementation
│   │   ├── element.cpp        # Element class implementation
│   │   ├── async-workers.cpp  # Async operation workers
│   │   └── type-conversion.cpp # Type conversion utilities
│   └── ts/                    # TypeScript implementation
│       ├── index.ts           # Main API exports and types
│       └── *.test.ts          # Comprehensive test suite
├── examples/                  # Usage examples
│   ├── basic-pipeline.mjs     # Simple pipeline example
│   ├── appsink.mjs           # AppSink usage
│   ├── appsrc.mjs            # AppSrc usage
│   ├── appsrc-eos.mjs        # AppSrc with end-of-stream
│   ├── record-to-file.mjs    # Recording to file example
│   ├── rtp-timestamp.mjs     # RTP handling
│   ├── bus.mjs               # Message bus handling
│   ├── seek.mjs              # Seeking functionality
│   ├── query.mjs             # Position/duration queries
│   ├── set-pad.mjs           # Pad manipulation
│   ├── fakesink.mjs          # Fakesink usage
│   └── glshader.mjs          # OpenGL shader example
├── build/                     # GYP build output
├── dist/                      # Rollup build output
│   ├── esm/                  # ES modules
│   ├── cjs/                  # CommonJS modules
│   └── index.d.ts            # Type definitions
├── scripts/                   # Build and utility scripts
├── binding.gyp               # GYP build configuration
├── rollup.config.mjs         # Rollup bundler configuration
├── vitest.config.ts          # Vitest test configuration
├── tsconfig.json             # TypeScript configuration
└── package.json              # Node.js package configuration

Performance Considerations

  • Concurrent Testing: All tests run concurrently for faster execution
  • Efficient Memory Management: Proper buffer lifecycle management
  • Async Operations: Non-blocking operations for better performance
  • Type Safety: Compile-time error detection reduces runtime overhead

Runtime Compatibility

| Runtime | Support Level | Notes | | ----------- | ---------------- | --------------------------- | | Node.js 16+ | ✅ Full | Minimal version | | Node.js 22+ | ✅ Full | Latest stable support | | Bun 1.0+ | ✅ Full | Alternative runtime support | | Deno | ❌ Not supported | Native module limitations |

Platform Compatibility

| Platform | Local Development | Production Ready | Notes | | ------------ | ----------------- | ---------------- | -------------------------- | | Ubuntu/Linux | ✅ Full | ✅ Full | Excellent for servers | | macOS | ✅ Full | ✅ Full | Intel and Apple Silicon | | Windows | ✅ Full | ✅ Full | Requires environment setup | | Docker | ✅ Full | ✅ Full | Ubuntu-based containers |

License

MIT License - see LICENSE file for details.

Contributing

See CONTRIBUTING.md for development setup and contribution guidelines.