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
ProcessManagerclass 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-Durationheader - 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
ProcessManagerfor 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 heartbeatDELETE /api/heartbeat- Notify player disconnectGET /api/heartbeat- Get status of all active players
Process Management
GET /api/processes- Get status of all active processesDELETE /api/processes- Cleanup all processesDELETE /api/processes?videoId=123- Cleanup processes for specific video
Transcoding
GET /api/stream/{id}/transcode- Start transcoding streamDELETE /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
- Video player generates unique
playerId - Starts sending heartbeats every 5 seconds to
/api/heartbeat - Backend tracks the player and associates it with the video ID
2. Transcoding Starts
- When transcoding is needed, FFmpeg process is started
- Process is registered with
ProcessManagerusing the video ID - Player continues sending heartbeats while transcoding
- Duration is discovered progressively as the stream progresses
3. Progress Bar Works
- For direct streams: Duration is fetched from
X-Content-Durationheader - For transcoded streams: Duration is discovered progressively via
durationchangeevents - Duration is validated to prevent NaN values
- Progress calculation uses validated duration and current time
- Progress clicks are validated before seeking
4. Player Closes
- Player stops sending heartbeats
- After 10 seconds without heartbeat, backend automatically:
- Removes player from active list
- Cleans up all FFmpeg processes for that video ID
- 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
- Reliable Cleanup: Heartbeat mechanism ensures FFmpeg processes are always cleaned up
- Resource Efficiency: No more orphaned processes consuming system resources
- Better UX: Accurate progress bars and visual feedback
- Monitoring: Admin tools to track active players and processes
- Transparency: Users can see when transcoding is active
- Fault Tolerance: Handles browser crashes, network issues, and unexpected closures
- Progressive Duration: Progress bar works correctly for transcoded videos without jumping
- Live-like Streaming: Proper handling of progressive duration discovery
- Smooth Progress: No more jumping when duration is discovered
Future Improvements
- Progress Tracking: Real-time transcoding progress updates via heartbeat
- Quality Selection: User-selectable transcoding quality
- Caching: Cache transcoded videos to avoid re-transcoding
- Queue Management: Handle multiple concurrent transcoding requests
- Error Recovery: Automatic retry mechanisms for failed transcoding
- Heartbeat Optimization: Reduce heartbeat frequency for better performance
- Progress Smoothing: Add interpolation for smoother progress updates
- Duration Caching: Cache duration values to avoid repeated fetches