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 🙏

© 2025 – Pkg Stats / Ryan Hefner

ffmpeg-stream-manager

v1.0.3

Published

🎥 A powerful TypeScript library for managing multiple simultaneous RTMP streams using FFmpeg. Perfect for streaming to platforms like YouTube Live, Twitch, and others.

Downloads

8

Readme

🎥 FFmpegStreamManager

npm version TypeScript License: MIT Node.js

Uma biblioteca poderosa em TypeScript para gerenciar múltiplas transmissões RTMP simultâneas usando FFmpeg. Ideal para streaming para plataformas como YouTube Live, Twitch e outras que suportam RTMP.

📖 Índice

🚀 Características

✨ Funcionalidades Principais

  • 🔄 Múltiplas transmissões simultâneas: Gerencie até N streams em paralelo
  • 🎯 Suporte completo ao YouTube Live: Configurações otimizadas para RTMP
  • 📹 Tipos de entrada flexíveis:
    • Arquivos de vídeo (.mp4, .avi, .mov, .mkv, etc.) - ÚNICO ou MÚLTIPLOS
    • Arquivos de áudio (.mp3, .wav, .aac, .flac) com imagem estática - PLAYLIST
    • Geradores FFmpeg (testsrc, anullsrc, color, etc.)
    • 🎵 Playlists automáticas: Múltiplos arquivos em sequência com loop infinito
  • ♾️ Loop infinito: Reinicialização automática quando o arquivo termina
  • 🔄 Reinício automático: Recuperação automática de falhas
  • ⚙️ Gerenciamento completo: Iniciar, parar, pausar, retomar e atualizar configurações
  • 📊 Logs detalhados: Captura completa de stdout/stderr do FFmpeg
  • 🛡️ TypeScript 100%: Tipagem forte e segura
  • 🔍 Monitoramento em tempo real: Status, uptime, logs por stream
  • 🚫 Sem dependências web: Biblioteca pura para uso interno

🎛️ Controles Avançados

  • Configuração dinâmica de bitrate, resolução e codec
  • Eventos em tempo real para todos os estados do stream
  • Filtros de log por stream ID e nível
  • Configurações otimizadas para diferentes plataformas
  • Gerenciamento automático de recursos

📦 Instalação

npm install ffmpeg-stream-manager

Pré-requisitos:

  • Node.js: 16.0 ou superior
  • FFmpeg: 4.0 ou superior instalado no sistema
  • TypeScript: 4.5+ (para desenvolvimento)

Instalação do FFmpeg

Ubuntu/Debian:

sudo apt update && sudo apt install ffmpeg

CentOS/RHEL/Fedora:

sudo dnf install ffmpeg

macOS:

brew install ffmpeg

Windows:

🔧 Uso Rápido

import { FFmpegStreamManager } from 'ffmpeg-stream-manager';

async function exemploRapido() {
  // Criar gerenciador
  const manager = new FFmpegStreamManager({
    maxConcurrentStreams: 5,
    autoRestart: true,
    logLevel: 'info'
  });

  // Configurar eventos
  manager.on('stream-started', (streamId) => {
    console.log(`✅ Stream iniciado: ${streamId}`);
  });

  manager.on('stream-error', (streamId, error) => {
    console.error(`❌ Erro: ${error.message}`);
  });

  try {
    // Iniciar stream para YouTube
    const streamId = await manager.startYouTubeStream(
      {
        inputType: 'video',
        inputPath: '/caminho/para/video.mp4',
        staticImagePath: undefined,
        loop: true,
        ...FFmpegStreamManager.getDefaultConfigs().youTube1080p
      },
      {
        streamKey: 'sua-chave-youtube',
        server: undefined // usa servidor padrão
      }
    );

    console.log(`🎥 Stream ativo: ${streamId}`);

    // Monitorar status
    const status = manager.getStreamStatus(streamId);
    console.log(`Status: ${status.status}, Uptime: ${status.uptime}s`);

  } catch (error) {
    console.error('Erro:', error);
  } finally {
    // Limpar recursos
    await manager.destroy();
  }
}

📚 API Completa

FFmpegStreamManager

Constructor

new FFmpegStreamManager(options?: StreamManagerOptions)

Parâmetros:

interface StreamManagerOptions {
  maxConcurrentStreams?: number;  // Limite de streams (padrão: 10)
  autoRestart?: boolean;          // Auto-restart em falhas (padrão: true)
  restartDelay?: number;          // Delay entre restarts em ms (padrão: 5000)
  logLevel?: 'debug' | 'info' | 'warning' | 'error'; // Nível de log (padrão: 'info')
}

Métodos Principais

startStream(config: StreamConfig): Promise<string>

Inicia um novo stream com configuração personalizada.

const streamId = await manager.startStream({
  rtmpUrl: 'rtmp://servidor.com/live/chave',
  inputType: 'video',
  inputPath: '/caminho/video.mp4',
  staticImagePath: undefined,
  loop: true,
  videoConfig: {
    width: 1920,
    height: 1080,
    bitrate: '4500k',
    framerate: 30,
    codec: 'libx264',
    profile: 'high',
    level: '4.1'
  },
  audioConfig: {
    codec: 'aac',
    bitrate: '128k',
    sampleRate: 44100,
    channels: 2
  },
  presetConfig: {
    preset: 'fast',
    tune: 'zerolatency',
    bufsize: '9000k',
    maxrate: '4500k'
  }
});
startYouTubeStream(config, youtubeConfig): Promise<string>

Inicia um stream otimizado para YouTube Live.

const streamId = await manager.startYouTubeStream(
  {
    inputType: 'audio',
    inputPath: '/caminho/audio.mp3',
    staticImagePath: '/caminho/imagem.jpg',
    loop: true,
    ...FFmpegStreamManager.getDefaultConfigs().youTube720p
  },
  {
    streamKey: 'sua-chave-youtube',
    server: 'rtmp://a.rtmp.youtube.com/live2/' // opcional
  }
);
stopStream(streamId: string): Promise<void>

Para um stream específico.

restartStream(streamId: string): Promise<void>

Reinicia um stream.

updateStreamConfig(streamId: string, updates: StreamUpdate): void

Atualiza configurações (stream deve estar parado).

getStreamStatus(streamId: string): StreamStatus

Obtém status detalhado de um stream.

getAllStreamStatuses(): StreamStatus[]

Obtém status de todos os streams.

getActiveStreamIds(): string[]

Lista IDs dos streams ativos.

stopAllStreams(): Promise<void>

Para todos os streams.

destroy(): Promise<void>

Limpa todos os recursos.

Configurações Pré-definidas

const configs = FFmpegStreamManager.getDefaultConfigs();

// Disponíveis:
// - youTube1080p: 1920x1080 @ 4500k
// - youTube720p:  1280x720  @ 2500k
// - youTube480p:  854x480   @ 1000k

🎬 Exemplos Detalhados

Stream de Vídeo para YouTube

import { FFmpegStreamManager } from 'ffmpeg-stream-manager';

async function streamVideoYoutube() {
  const manager = new FFmpegStreamManager();

  const streamId = await manager.startYouTubeStream(
    {
      inputType: 'video',
      inputPath: '/videos/meu-video.mp4',
      staticImagePath: undefined,
      loop: true,
      ...FFmpegStreamManager.getDefaultConfigs().youTube1080p
    },
    {
      streamKey: 'abcd-efgh-ijkl-mnop'
    }
  );

  console.log(`Stream iniciado: ${streamId}`);
}

Stream de Áudio com Imagem Estática

async function streamAudioComImagem() {
  const manager = new FFmpegStreamManager();

  const streamId = await manager.startStream({
    rtmpUrl: 'rtmp://live.twitch.tv/live/sua-chave',
    inputType: 'audio',
    inputPath: '/audio/musica.mp3',
    staticImagePath: '/imagens/capa.jpg',
    loop: true,
    videoConfig: {
      width: 1280,
      height: 720,
      bitrate: '2500k',
      framerate: 30,
      codec: 'libx264',
      profile: 'main',
      level: '3.1'
    },
    audioConfig: {
      codec: 'aac',
      bitrate: '128k',
      sampleRate: 44100,
      channels: 2
    },
    presetConfig: {
      preset: 'fast',
      tune: 'zerolatency',
      bufsize: '5000k',
      maxrate: '2500k'
    }
  });

  return streamId;
}

Múltiplos Streams Simultâneos

async function multiplosStreams() {
  const manager = new FFmpegStreamManager({
    maxConcurrentStreams: 3
  });

  const streams = await Promise.allSettled([
    manager.startYouTubeStream(configYoutube1, { streamKey: 'key1' }),
    manager.startYouTubeStream(configYoutube2, { streamKey: 'key2' }),
    manager.startStream(configTwitch)
  ]);

  streams.forEach((result, index) => {
    if (result.status === 'fulfilled') {
      console.log(`Stream ${index + 1} iniciado: ${result.value}`);
    } else {
      console.error(`Stream ${index + 1} falhou: ${result.reason}`);
    }
  });
}

Stream com Múltiplos Arquivos

async function streamMultiplosArquivos() {
  const manager = new FFmpegStreamManager();

  // Múltiplos vídeos em sequência (playlist)
  const videoStreamId = await manager.startYouTubeStream({
    inputType: 'video',
    inputPath: [
      '/videos/intro.mp4',
      '/videos/episodio1.mp4',
      '/videos/episodio2.mp4',
      '/videos/outro.mp4'
    ], // Array de arquivos
    staticImagePath: undefined,
    loop: true, // Repete a playlist infinitamente
    ...FFmpegStreamManager.getDefaultConfigs().youTube1080p
  }, {
    streamKey: 'sua-chave-youtube'
  });

  // Múltiplos áudios com imagem estática
  const audioStreamId = await manager.startStream({
    rtmpUrl: 'rtmp://live.twitch.tv/live/chave',
    inputType: 'audio',
    inputPath: [
      '/musicas/track1.mp3',
      '/musicas/track2.mp3',
      '/musicas/track3.mp3'
    ], // Playlist de músicas
    staticImagePath: '/imagens/capa-album.jpg',
    loop: true, // Radio 24/7
    videoConfig: {
      width: 1280,
      height: 720,
      bitrate: '2500k',
      framerate: 30,
      codec: 'libx264',
      profile: 'main',
      level: '3.1'
    },
    audioConfig: {
      codec: 'aac',
      bitrate: '128k',
      sampleRate: 44100,
      channels: 2
    },
    presetConfig: {
      preset: 'fast',
      tune: 'zerolatency',
      bufsize: '5000k',
      maxrate: '2500k'
    }
  });

  return { videoStreamId, audioStreamId };
}

Stream com Gerador FFmpeg

async function streamGenerado() {
  const manager = new FFmpegStreamManager();

  // Stream de cor sólida com áudio silencioso
  const streamId = await manager.startStream({
    rtmpUrl: 'rtmp://servidor.com/live/test',
    inputType: 'video',
    inputPath: 'color=blue:size=1920x1080:rate=30',
    staticImagePath: undefined,
    loop: true,
    ...FFmpegStreamManager.getDefaultConfigs().youTube720p
  });

  return streamId;
}

⚙️ Configurações

StreamConfig Interface

interface StreamConfig {
  id: string;                              // Auto-gerado (UUID v4)
  rtmpUrl: string;                         // URL RTMP de destino
  inputType: 'video' | 'audio';            // Tipo de entrada
  inputPath: string | string[];            // Arquivo único ou múltiplos (playlist)
  staticImagePath: string | undefined;     // Imagem para streams de áudio
  loop: boolean;                           // Loop infinito
  videoConfig: VideoConfig;                // Configurações de vídeo
  audioConfig: AudioConfig;                // Configurações de áudio
  presetConfig: PresetConfig;              // Configurações de preset
}

VideoConfig Interface

interface VideoConfig {
  width: number;                           // Largura em pixels
  height: number;                          // Altura em pixels
  bitrate: string;                         // Taxa de bits (ex: "4500k")
  framerate: number;                       // FPS (ex: 30)
  codec: string;                           // Codec (ex: "libx264")
  profile: string | undefined;             // Perfil H.264 (ex: "high")
  level: string | undefined;               // Nível H.264 (ex: "4.1")
}

AudioConfig Interface

interface AudioConfig {
  codec: string;                           // Codec (ex: "aac")
  bitrate: string;                         // Taxa de bits (ex: "128k")
  sampleRate: number;                      // Taxa de amostragem (ex: 44100)
  channels: number;                        // Canais (ex: 2 para estéreo)
}

PresetConfig Interface

interface PresetConfig {
  preset: string;                          // Preset FFmpeg (ex: "fast")
  tune: string | undefined;                // Tunning (ex: "zerolatency")
  bufsize: string | undefined;             // Buffer size (ex: "5000k")
  maxrate: string | undefined;             // Taxa máxima (ex: "2500k")
}

📡 Eventos

Configurando Event Listeners

const manager = new FFmpegStreamManager();

// Stream iniciado
manager.on('stream-started', (streamId: string) => {
  console.log(`✅ Stream iniciado: ${streamId}`);
});

// Stream parado
manager.on('stream-stopped', (streamId: string) => {
  console.log(`⏹️ Stream parado: ${streamId}`);
});

// Erro no stream
manager.on('stream-error', (streamId: string, error: Error) => {
  console.error(`❌ Erro no stream ${streamId}: ${error.message}`);
});

// Stream reiniciado
manager.on('stream-restarted', (streamId: string) => {
  console.log(`🔄 Stream reiniciado: ${streamId}`);
});

// Logs do FFmpeg
manager.on('log', (log: FFmpegLog) => {
  console.log(`[${log.level}] [${log.streamId}] ${log.message}`);
});

Filtrando Logs por Stream

// Logs de um stream específico
manager.on('log', (log) => {
  if (log.streamId === 'meu-stream-id') {
    console.log(`Log específico: ${log.message}`);
  }
});

// Apenas logs de erro
manager.on('log', (log) => {
  if (log.level === 'error') {
    console.error(`❌ Erro: ${log.message}`);
  }
});

// Excluir logs do manager
manager.on('log', (log) => {
  if (log.streamId !== 'manager') {
    console.log(`Stream log: ${log.message}`);
  }
});

🚨 Tratamento de Erros

Try-Catch Básico

try {
  const streamId = await manager.startStream(config);
  console.log('Stream iniciado com sucesso');
} catch (error) {
  if (error instanceof StreamError) {
    console.error(`Erro no stream ${error.streamId}: ${error.message}`);
  } else {
    console.error('Erro desconhecido:', error);
  }
}

Event Listeners para Erros

manager.on('stream-error', (streamId, error) => {
  console.error(`Stream ${streamId} falhou: ${error.message}`);
  
  // Tentar reiniciar após 5 segundos
  setTimeout(async () => {
    try {
      await manager.restartStream(streamId);
      console.log(`Stream ${streamId} reiniciado com sucesso`);
    } catch (restartError) {
      console.error(`Falha ao reiniciar stream ${streamId}:`, restartError);
    }
  }, 5000);
});

Validação de Configuração

import { FFmpegCommandBuilder } from 'ffmpeg-stream-manager';

try {
  FFmpegCommandBuilder.validateConfig(config);
  console.log('Configuração válida');
} catch (error) {
  console.error('Configuração inválida:', error.message);
}

📊 Logs e Monitoramento

Monitoramento em Tempo Real

// Monitorar todos os streams a cada 30 segundos
setInterval(() => {
  const statuses = manager.getAllStreamStatuses();
  
  console.log(`\n📊 Status dos Streams (${statuses.length} total):`);
  
  statuses.forEach(status => {
    const emoji = status.status === 'running' ? '🟢' : 
                  status.status === 'error' ? '🔴' : '🟡';
    
    console.log(`${emoji} ${status.id}:`);
    console.log(`   Status: ${status.status}`);
    console.log(`   Uptime: ${status.uptime}s`);
    console.log(`   Restarts: ${status.restartCount}`);
    
    if (status.lastError) {
      console.log(`   Last Error: ${status.lastError}`);
    }
  });
}, 30000);

Sistema de Logs Personalizado

class StreamLogger {
  private logFile: string;
  
  constructor(logFile: string) {
    this.logFile = logFile;
  }
  
  setupLogging(manager: FFmpegStreamManager) {
    manager.on('log', (log) => {
      const timestamp = log.timestamp.toISOString();
      const logLine = `${timestamp} [${log.level}] [${log.streamId}] ${log.message}\n`;
      
      // Escrever no arquivo (usando fs)
      fs.appendFileSync(this.logFile, logLine);
      
      // Console apenas para erros
      if (log.level === 'error') {
        console.error(logLine.trim());
      }
    });
    
    manager.on('stream-started', (streamId) => {
      this.logEvent('STARTED', streamId);
    });
    
    manager.on('stream-stopped', (streamId) => {
      this.logEvent('STOPPED', streamId);
    });
  }
  
  private logEvent(event: string, streamId: string) {
    const timestamp = new Date().toISOString();
    const logLine = `${timestamp} [EVENT] [${streamId}] ${event}\n`;
    fs.appendFileSync(this.logFile, logLine);
  }
}

// Uso
const logger = new StreamLogger('./streams.log');
logger.setupLogging(manager);

🔧 Tipos TypeScript

StreamStatus Interface

interface StreamStatus {
  id: string;                              // ID único do stream
  status: StreamState;                     // Estado atual
  startTime: Date | undefined;             // Hora de início
  uptime: number | undefined;              // Tempo ativo em segundos
  restartCount: number;                    // Número de reinicializações
  lastError: string | undefined;           // Último erro
  ffmpegPid: number | undefined;           // PID do processo FFmpeg
  config: StreamConfig;                    // Configuração do stream
}

StreamState Enum

enum StreamState {
  STOPPED = 'stopped',
  STARTING = 'starting',
  RUNNING = 'running',
  PAUSED = 'paused',
  ERROR = 'error',
  RESTARTING = 'restarting'
}

FFmpegLog Interface

interface FFmpegLog {
  streamId: string;                        // ID do stream
  timestamp: Date;                         // Timestamp do log
  level: 'info' | 'error' | 'warning';     // Nível do log
  message: string;                         // Mensagem
  source: 'stdout' | 'stderr';             // Origem do log
}

StreamUpdate Interface

interface StreamUpdate {
  rtmpUrl?: string;                        // Nova URL RTMP
  inputPath?: string | string[];           // Novos arquivos (playlist)
  videoConfig?: Partial<VideoConfig>;      // Atualizações de vídeo
  audioConfig?: Partial<AudioConfig>;      // Atualizações de áudio
  presetConfig?: Partial<PresetConfig>;    // Atualizações de preset
  loop?: boolean;                          // Alterar loop
}

🎛️ Configurações Pré-definidas

YouTube Presets

const configs = FFmpegStreamManager.getDefaultConfigs();

// 1080p - Alta qualidade
configs.youTube1080p = {
  videoConfig: {
    width: 1920,
    height: 1080,
    bitrate: '4500k',
    framerate: 30,
    codec: 'libx264',
    profile: 'high',
    level: '4.1'
  },
  audioConfig: {
    codec: 'aac',
    bitrate: '128k',
    sampleRate: 44100,
    channels: 2
  },
  presetConfig: {
    preset: 'fast',
    tune: 'zerolatency',
    bufsize: '9000k',
    maxrate: '4500k'
  }
};

// 720p - Qualidade média
configs.youTube720p = {
  videoConfig: {
    width: 1280,
    height: 720,
    bitrate: '2500k',
    framerate: 30,
    codec: 'libx264',
    profile: 'high',
    level: '3.1'
  },
  audioConfig: {
    codec: 'aac',
    bitrate: '128k',
    sampleRate: 44100,
    channels: 2
  },
  presetConfig: {
    preset: 'fast',
    tune: 'zerolatency',
    bufsize: '5000k',
    maxrate: '2500k'
  }
};

// 480p - Baixa qualidade
configs.youTube480p = {
  videoConfig: {
    width: 854,
    height: 480,
    bitrate: '1000k',
    framerate: 30,
    codec: 'libx264',
    profile: 'main',
    level: '3.0'
  },
  audioConfig: {
    codec: 'aac',
    bitrate: '96k',
    sampleRate: 44100,
    channels: 2
  },
  presetConfig: {
    preset: 'fast',
    tune: 'zerolatency',
    bufsize: '2000k',
    maxrate: '1000k'
  }
};

Configurações Personalizadas

// Para Twitch
const twitchConfig = {
  videoConfig: {
    width: 1920,
    height: 1080,
    bitrate: '6000k',        // Twitch permite até 6Mbps
    framerate: 60,           // 60 FPS para jogos
    codec: 'libx264',
    profile: 'main',
    level: '4.1'
  },
  audioConfig: {
    codec: 'aac',
    bitrate: '160k',         // Áudio de alta qualidade
    sampleRate: 48000,       // 48kHz recomendado
    channels: 2
  },
  presetConfig: {
    preset: 'veryfast',      // Preset mais rápido para menos latência
    tune: 'zerolatency',
    bufsize: '12000k',
    maxrate: '6000k'
  }
};

// Para Facebook Live
const facebookConfig = {
  videoConfig: {
    width: 1280,
    height: 720,
    bitrate: '4000k',
    framerate: 30,
    codec: 'libx264',
    profile: 'baseline',     // Facebook prefere baseline
    level: '3.1'
  },
  audioConfig: {
    codec: 'aac',
    bitrate: '128k',
    sampleRate: 44100,
    channels: 2
  },
  presetConfig: {
    preset: 'fast',
    tune: undefined,         // Sem tune específico
    bufsize: '8000k',
    maxrate: '4000k'
  }
};

📋 Requisitos do Sistema

Requisitos Mínimos

  • Node.js: 16.0.0 ou superior
  • FFmpeg: 4.0 ou superior
  • RAM: 512MB disponível
  • CPU: Depende da resolução e número de streams
  • Largura de banda: Conforme bitrate configurado

Requisitos Recomendados

  • Node.js: 18.0.0 ou superior
  • FFmpeg: 5.0 ou superior (melhor performance)
  • RAM: 2GB+ para múltiplos streams
  • CPU: Processador multi-core
  • SSD: Para melhor I/O de arquivos

Performance Guidelines

| Resolução | Streams Simultâneos | CPU Recomendado | RAM Recomendada | |-----------|---------------------|-----------------|-----------------| | 480p | 1-3 | 2 cores | 1GB | | 720p | 1-2 | 4 cores | 2GB | | 1080p | 1 | 6+ cores | 4GB |

Estimativa de Uso de CPU

// Exemplo de monitoramento de recursos
async function monitorarRecursos() {
  const manager = new FFmpegStreamManager();
  
  manager.on('stream-started', (streamId) => {
    const status = manager.getStreamStatus(streamId);
    console.log(`Stream ${streamId} - PID: ${status.ffmpegPid}`);
    
    // Monitorar CPU do processo (usando bibliotecas como 'pidusage')
    // pidusage(status.ffmpegPid, (err, stats) => {
    //   console.log(`CPU: ${stats.cpu}%, Memory: ${stats.memory} bytes`);
    // });
  });
}

❓ FAQ

Q: Como funciona o ID dos streams?

A: O streamID é gerado automaticamente usando UUID v4, garantindo unicidade global. Formato: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx.

Q: Como usar múltiplos arquivos em loop?

A: Use um array de strings no inputPath:

{
  inputPath: [
    '/videos/parte1.mp4',
    '/videos/parte2.mp4',
    '/videos/parte3.mp4'
  ],
  loop: true // Repete a sequência infinitamente
}

Q: Os arquivos são reproduzidos em ordem?

A: Sim, os arquivos são reproduzidos na ordem exata do array. Para ordem aleatória, embaralhe o array antes:

const files = ['/video1.mp4', '/video2.mp4', '/video3.mp4'];
const shuffled = files.sort(() => Math.random() - 0.5);

Q: Posso misturar diferentes formatos?

A: Sim, mas todos devem ser do mesmo tipo (vídeo ou áudio). FFmpeg normalizará automaticamente:

inputPath: [
  '/videos/arquivo.mp4',
  '/videos/outro.avi',
  '/videos/terceiro.mov'
]

Q: Posso usar arquivos em rede (URLs HTTP)?

A: Sim, o FFmpeg suporta URLs HTTP/HTTPS como entrada:

{
  inputPath: 'https://exemplo.com/video.mp4',
  // ...
}

Q: Como otimizar para low latency?

A: Use estas configurações:

{
  presetConfig: {
    preset: 'ultrafast',
    tune: 'zerolatency',
    bufsize: '1000k'  // Buffer menor
  }
}

Q: Posso fazer stream sem arquivo (webcam/tela)?

A: Esta biblioteca é focada em arquivos. Para webcam/tela, use geradores FFmpeg:

{
  inputPath: ':0.0+10,10',  // Tela no Windows
  // ou
  inputPath: '/dev/video0'  // Webcam no Linux
}

Q: Como tratar streams que param inesperadamente?

A: Use auto-restart e monitore eventos:

const manager = new FFmpegStreamManager({
  autoRestart: true,
  restartDelay: 3000
});

manager.on('stream-error', async (streamId, error) => {
  console.error(`Stream ${streamId} erro: ${error.message}`);
  
  // Lógica personalizada de restart
  if (error.message.includes('Connection refused')) {
    // Aguardar mais tempo para reconnect
    await new Promise(resolve => setTimeout(resolve, 10000));
    await manager.restartStream(streamId);
  }
});

Q: Qual codec usar para melhor qualidade?

A: Depende do caso:

  • H.264 (libx264): Mais compatível, boa qualidade
  • H.265 (libx265): Melhor compressão, requer mais CPU
  • Para YouTube: H.264 é recomendado
  • Para baixa latência: H.264 com tune zerolatency

Q: Como verificar se FFmpeg está instalado?

A:

ffmpeg -version

Se não retornar versão, instale conforme seu OS.

Q: Posso usar com Docker?

A: Sim, use uma imagem com Node.js + FFmpeg:

FROM node:18
RUN apt-get update && apt-get install -y ffmpeg
COPY . .
RUN npm install
CMD ["npm", "start"]

Q: Como fazer debug de problemas?

A:

  1. Ative logs debug: logLevel: 'debug'
  2. Monitore eventos de erro
  3. Teste comando FFmpeg manualmente
  4. Verifique permissões de arquivo

🤝 Contribuição

Contribuições são muito bem-vindas!

Como Contribuir

  1. Fork o repositório
  2. Crie uma branch para sua feature (git checkout -b feature/AmazingFeature)
  3. Commit suas mudanças (git commit -m 'Add some AmazingFeature')
  4. Push para a branch (git push origin feature/AmazingFeature)
  5. Abra um Pull Request

Diretrizes

  • ✅ Mantenha 100% cobertura de tipos TypeScript
  • ✅ Adicione testes para novas funcionalidades
  • ✅ Siga o padrão de código existente
  • ✅ Documente mudanças no README
  • ✅ Teste com múltiplas versões do Node.js

Desenvolvimento Local

# Clone o repositório
git clone https://github.com/seu-usuario/ffmpeg-stream-manager.git
cd ffmpeg-stream-manager

# Instale dependências
npm install

# Desenvolvimento com watch
npm run dev

# Executar testes
npm test

# Build
npm run build

# Lint
npm run lint

📄 Licença

Este projeto está licenciado sob a MIT License - veja o arquivo LICENSE para detalhes.

🔗 Links Úteis

📊 Estatísticas

GitHub stars GitHub forks GitHub issues NPM downloads


Desenvolvido com ❤️ por [Seu Nome]

Se esta biblioteca foi útil para você, considere dar uma ⭐ no GitHub!