UNPKG

ffmpeg-stream-manager

Version:

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

1,073 lines (889 loc) 28.3 kB
# 🎥 FFmpegStreamManager [![npm version](https://badge.fury.io/js/ffmpeg-stream-manager.svg)](https://badge.fury.io/js/ffmpeg-stream-manager) [![TypeScript](https://img.shields.io/badge/TypeScript-100%25-blue.svg)](https://www.typescriptlang.org/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Node.js](https://img.shields.io/badge/Node.js-16%2B-green.svg)](https://nodejs.org/) > 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](#-características) - [Instalação](#-instalação) - [Uso Rápido](#-uso-rápido) - [API Completa](#-api-completa) - [Exemplos Detalhados](#-exemplos-detalhados) - [Configurações](#-configurações) - [Eventos](#-eventos) - [Tratamento de Erros](#-tratamento-de-erros) - [Logs e Monitoramento](#-logs-e-monitoramento) - [Tipos TypeScript](#-tipos-typescript) - [Configurações Pré-definidas](#-configurações-pré-definidas) - [Requisitos do Sistema](#-requisitos-do-sistema) - [FAQ](#-faq) - [Contribuição](#-contribuição) - [Licença](#-licença) ## 🚀 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 ```bash 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:** ```bash sudo apt update && sudo apt install ffmpeg ``` **CentOS/RHEL/Fedora:** ```bash sudo dnf install ffmpeg ``` **macOS:** ```bash brew install ffmpeg ``` **Windows:** - Baixe de [https://ffmpeg.org/download.html](https://ffmpeg.org/download.html) - Adicione ao PATH do sistema ## 🔧 Uso Rápido ```typescript 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 ```typescript new FFmpegStreamManager(options?: StreamManagerOptions) ``` **Parâmetros:** ```typescript 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. ```typescript 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. ```typescript 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 ```typescript const configs = FFmpegStreamManager.getDefaultConfigs(); // Disponíveis: // - youTube1080p: 1920x1080 @ 4500k // - youTube720p: 1280x720 @ 2500k // - youTube480p: 854x480 @ 1000k ``` ## 🎬 Exemplos Detalhados ### Stream de Vídeo para YouTube ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript // 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 ```typescript 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 ```typescript 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 ```typescript 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 ```typescript // 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 ```typescript 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 ```typescript 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 ```typescript enum StreamState { STOPPED = 'stopped', STARTING = 'starting', RUNNING = 'running', PAUSED = 'paused', ERROR = 'error', RESTARTING = 'restarting' } ``` ### FFmpegLog Interface ```typescript 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 ```typescript 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 ```typescript 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 ```typescript // 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 ```typescript // 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`: ```typescript { 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: ```typescript 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: ```typescript 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: ```typescript { inputPath: 'https://exemplo.com/video.mp4', // ... } ``` ### **Q: Como otimizar para low latency?** **A:** Use estas configurações: ```typescript { 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: ```typescript { 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: ```typescript 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:** ```bash 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: ```dockerfile 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 ```bash # 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](LICENSE) para detalhes. ## 🔗 Links Úteis - **NPM**: [https://www.npmjs.com/package/ffmpeg-stream-manager](https://www.npmjs.com/package/ffmpeg-stream-manager) - **GitHub**: [https://github.com/seu-usuario/ffmpeg-stream-manager](https://github.com/seu-usuario/ffmpeg-stream-manager) - **Issues**: [https://github.com/seu-usuario/ffmpeg-stream-manager/issues](https://github.com/seu-usuario/ffmpeg-stream-manager/issues) - **FFmpeg Docs**: [https://ffmpeg.org/documentation.html](https://ffmpeg.org/documentation.html) - **YouTube Live**: [https://support.google.com/youtube/answer/2907883](https://support.google.com/youtube/answer/2907883) ## 📊 Estatísticas ![GitHub stars](https://img.shields.io/github/stars/seu-usuario/ffmpeg-stream-manager?style=social) ![GitHub forks](https://img.shields.io/github/forks/seu-usuario/ffmpeg-stream-manager?style=social) ![GitHub issues](https://img.shields.io/github/issues/seu-usuario/ffmpeg-stream-manager) ![NPM downloads](https://img.shields.io/npm/dm/ffmpeg-stream-manager) --- **Desenvolvido com ❤️ por [Seu Nome]** *Se esta biblioteca foi útil para você, considere dar umano GitHub!*