nextav/TRANSCODING_FIXES.md

8.2 KiB

Transcoding Fixes Documentation

This document describes the fixes implemented to address two critical issues with the video transcoding functionality in NextAV.

Issues Addressed

1. FFmpeg Process Not Stopped When Video Viewer Closes

Problem: When users closed the video viewer, FFmpeg transcoding processes continued running in the background, consuming system resources.

Root Cause:

  • Inadequate cleanup mechanisms in the transcoding API
  • No global process tracking
  • Unreliable client disconnect detection

Solution:

  • Implemented a heartbeat mechanism for reliable player tracking
  • Created a global ProcessManager class to track all FFmpeg processes
  • Added automatic cleanup when heartbeat stops for more than 10 seconds
  • Created a DELETE endpoint for manual process termination
  • Added automatic cleanup of stale processes (older than 10 minutes)

2. Progress Bar Not Showing Correct Progress for Transcoding Streams

Problem: The video progress bar showed incorrect progress when playing transcoded streams, even though the duration was correctly retrieved. The progress bar would jump and the duration wasn't displaying correctly specifically when transcoding was required.

Root Cause:

  • Video player components weren't properly reading the X-Content-Duration header
  • Duration wasn't being set correctly for transcoded streams
  • Missing duration display in the UI
  • FFmpeg output format wasn't preserving duration metadata properly
  • Progress bar calculation wasn't handling invalid values correctly

Solution:

  • Enhanced video player components to read duration from response headers
  • Added proper duration handling for both direct and transcoded streams
  • Improved duration display in the UI
  • Added transcoding indicator to show when transcoding is active
  • Fixed FFmpeg configuration to preserve duration metadata
  • Improved progress bar calculation with better validation
  • Added duration change event handling for dynamic updates

Implementation Details

Heartbeat Mechanism (src/app/api/heartbeat/route.ts)

A reliable system for tracking active video players:

// Player sends heartbeat every 5 seconds
POST /api/heartbeat
{
  "playerId": "player_1234567890_abc123",
  "videoId": 53
}

// Player notifies disconnect
DELETE /api/heartbeat
{
  "playerId": "player_1234567890_abc123"
}

// Check active players
GET /api/heartbeat

Key Features:

  • 10-second timeout: If no heartbeat for 10 seconds, FFmpeg processes are cleaned up
  • Automatic cleanup: Background process checks every 5 seconds for stale heartbeats
  • Player tracking: Each player has a unique ID for reliable tracking
  • Video association: Heartbeats are linked to specific video IDs for targeted cleanup

Process Manager (src/lib/process-manager.ts)

A global singleton class that manages all FFmpeg processes:

class ProcessManager {
  // Register a new FFmpeg process
  register(processId: string, process: any, videoId: string, cleanup: () => void)
  
  // Remove a specific process
  remove(processId: string)
  
  // Remove all processes for a specific video
  removeByVideoId(videoId: string)
  
  // Get all active processes
  getAllProcesses()
}

Enhanced Transcoding API (src/app/api/stream/[id]/transcode/route.ts)

Key improvements:

  • Uses ProcessManager for process tracking
  • Simplified cleanup (now handled by heartbeat)
  • Proper duration header handling
  • DELETE endpoint for manual cleanup

Updated Video Player Components

Both InlineVideoPlayer and VideoViewer components now:

  • Send heartbeats: Every 5 seconds while player is open
  • Notify disconnect: When player closes or component unmounts
  • Track transcoding state: Show transcoding indicators
  • Read duration from headers: Proper progress bar support
  • Display duration information: Show video duration in UI

API Endpoints

Heartbeat Management

  • POST /api/heartbeat - Send player heartbeat
  • DELETE /api/heartbeat - Notify player disconnect
  • GET /api/heartbeat - Get status of all active players

Process Management

  • GET /api/processes - Get status of all active processes
  • DELETE /api/processes - Cleanup all processes
  • DELETE /api/processes?videoId=123 - Cleanup processes for specific video

Transcoding

  • GET /api/stream/{id}/transcode - Start transcoding stream
  • DELETE /api/stream/{id}/transcode - Stop transcoding for video

Testing

Test Progress Bar Fixes

node test-progress-bar.mjs

Test Heartbeat Mechanism

node test-heartbeat.mjs

Test Transcoding Fixes

node test-transcoding-fixes.mjs

Monitoring

Check Active Players

curl http://localhost:3000/api/heartbeat

Check Active Processes

curl http://localhost:3000/api/processes

Check Transcoding Headers

curl -I http://localhost:3000/api/stream/54/transcode

Cleanup Specific Video

curl -X DELETE "http://localhost:3000/api/processes?videoId=54"

Cleanup All Processes

curl -X DELETE http://localhost:3000/api/processes

Logs

The system now provides detailed logging:

[HEARTBEAT] Player player_1234567890_abc123 for video 54 pinged
[PROCESS_MANAGER] Registered process: transcode_54_1234567890 for video: 54
[TRANSCODE] Sending response with 1280x720 video stream (progressive duration)
[PLAYER] Duration from metadata: 581.4s
[PLAYER] Duration changed: 581.4s
[HEARTBEAT] Player player_1234567890_abc123 for video 54 timed out, cleaning up FFmpeg processes
[PROCESS_MANAGER] Removed process: transcode_54_1234567890

How It Works

1. Player Opens

  1. Video player generates unique playerId
  2. Starts sending heartbeats every 5 seconds to /api/heartbeat
  3. Backend tracks the player and associates it with the video ID

2. Transcoding Starts

  1. When transcoding is needed, FFmpeg process is started
  2. Process is registered with ProcessManager using the video ID
  3. Player continues sending heartbeats while transcoding
  4. Duration is discovered progressively as the stream progresses

3. Progress Bar Works

  1. For direct streams: Duration is fetched from X-Content-Duration header
  2. For transcoded streams: Duration is discovered progressively via durationchange events
  3. Duration is validated to prevent NaN values
  4. Progress calculation uses validated duration and current time
  5. Progress clicks are validated before seeking

4. Player Closes

  1. Player stops sending heartbeats
  2. After 10 seconds without heartbeat, backend automatically:
    • Removes player from active list
    • Cleans up all FFmpeg processes for that video ID
  3. Alternatively, player can explicitly notify disconnect via DELETE request

5. Automatic Cleanup

  • Background process runs every 5 seconds
  • Checks for heartbeats older than 10 seconds
  • Automatically cleans up associated FFmpeg processes
  • Prevents resource leaks from crashed or closed players

Benefits

  1. Reliable Cleanup: Heartbeat mechanism ensures FFmpeg processes are always cleaned up
  2. Resource Efficiency: No more orphaned processes consuming system resources
  3. Better UX: Accurate progress bars and visual feedback
  4. Monitoring: Admin tools to track active players and processes
  5. Transparency: Users can see when transcoding is active
  6. Fault Tolerance: Handles browser crashes, network issues, and unexpected closures
  7. Progressive Duration: Progress bar works correctly for transcoded videos without jumping
  8. Live-like Streaming: Proper handling of progressive duration discovery
  9. Smooth Progress: No more jumping when duration is discovered

Future Improvements

  1. Progress Tracking: Real-time transcoding progress updates via heartbeat
  2. Quality Selection: User-selectable transcoding quality
  3. Caching: Cache transcoded videos to avoid re-transcoding
  4. Queue Management: Handle multiple concurrent transcoding requests
  5. Error Recovery: Automatic retry mechanisms for failed transcoding
  6. Heartbeat Optimization: Reduce heartbeat frequency for better performance
  7. Progress Smoothing: Add interpolation for smoother progress updates
  8. Duration Caching: Cache duration values to avoid repeated fetches