7.9 KiB
MPEG Transport Stream (.ts) File Handling Guide
Overview
MPEG Transport Stream (.ts) files are a common video container format that present unique opportunities for efficient web streaming. This guide explains the characteristics of .ts files and optimal handling strategies.
Understanding .ts Files
What are .ts files?
.ts files are MPEG Transport Stream containers that:
- Contain already-encoded video and audio streams - typically H.264 video and AAC audio
- Are designed for streaming and broadcast - specifically created for reliable transmission over networks
- Are the native format used by HLS (HTTP Live Streaming) - HLS breaks videos into .ts segments
- Can be "converted" instantly using container remuxing (no re-encoding needed)
Why .ts files from streaming sites work well
Downloaded .ts files from video streaming sites (like the ones you mentioned) are particularly suitable because:
- They already contain web-compatible codecs (H.264/AAC)
- They're optimized for streaming (proper keyframe intervals, constant bitrates)
- They're single-segment streams (entire video in one .ts file)
- They have proper metadata for duration and seeking
Technical Characteristics
Container vs. Codec
┌─────────────────┐ ┌──────────────────┐
│ .ts Container │ │ .mp4 Container │
├─────────────────┤ ├──────────────────┤
│ H.264 Video ────┼────┼──► H.264 Video │
│ AAC Audio ────┼────┼──► AAC Audio │
└─────────────────┘ └──────────────────┘
Same codecs, different container
Browser Compatibility
| Format | Chrome | Firefox | Safari | Edge | Notes |
|---|---|---|---|---|---|
| .ts direct | ❌ | ❌ | ❌ | ❌ | Browsers don't support .ts containers |
| .ts via HLS | ✅ | ✅ | ✅ | ✅ | With hls.js library |
| .mp4 (converted) | ✅ | ✅ | ✅ | ✅ | Native browser support |
Implementation Strategies
Strategy 1: HLS Streaming (Recommended)
Best for: Downloaded .ts files from streaming sites
// Current implementation in video-format-detector.ts
if (TS_STREAM_FORMATS.includes(extension)) {
return createTSHLSFormat(video, extension);
}
Advantages:
- ✅ Works with all browsers (via hls.js)
- ✅ No conversion needed
- ✅ Proper seeking and buffering
- ✅ Leverages existing HLS infrastructure
How it works:
- Generate M3U8 playlist pointing to the .ts file as a single segment
- Serve the entire .ts file when segment 0 is requested
- Browser uses hls.js to handle the stream
Strategy 2: Container Conversion
Best for: Maximum browser compatibility
# Fast container remuxing (seconds, not minutes)
ffmpeg -i input.ts -c copy -movflags +faststart output.mp4
Advantages:
- ✅ Native browser support (no JavaScript libraries needed)
- ✅ Maximum compatibility
- ✅ Optimized for web (faststart flag)
- ✅ Very fast (container remuxing only)
API Usage:
// Convert .ts to .mp4
POST /api/videos/{id}/convert-ts
{
"fastStart": true,
"deleteOriginal": false
}
Strategy 3: Direct Streaming
Best for: External players
// Serve .ts file directly with proper MIME type
headers: {
'Content-Type': 'video/mp2t',
'Accept-Ranges': 'bytes'
}
Advantages:
- ✅ No processing needed
- ✅ Works with VLC, MPV, etc.
- ✅ Full range request support
Current Implementation
Format Detection
// src/lib/video-format-detector.ts
const TS_STREAM_FORMATS = ['ts', 'm2ts', 'mts'];
if (TS_STREAM_FORMATS.includes(extension)) {
return createTSHLSFormat(video, extension); // Default to HLS
}
HLS Playlist Generation
// src/app/api/stream/hls/[id]/playlist.m3u8/route.ts
function generateTSFilePlaylist(video: any, videoId: number): Response {
const playlist = [
'#EXTM3U',
'#EXT-X-VERSION:3',
`#EXT-X-TARGETDURATION:${Math.ceil(duration)}`,
'#EXT-X-MEDIA-SEQUENCE:0',
`#EXTINF:${duration.toFixed(3)},`,
'../segment/0.ts',
'#EXT-X-ENDLIST'
].join('\n');
}
Segment Serving
// src/app/api/stream/hls/[id]/segment/[segment]/route.ts
if (fileExtension === '.ts' && segmentIndex === 0) {
// Serve entire .ts file as segment 0
const file = fs.createReadStream(videoPath);
return new Response(file, {
headers: {
'Content-Type': 'video/mp2t',
'Accept-Ranges': 'bytes'
}
});
}
Testing and Validation
Test Suite
Run the comprehensive test suite:
node test-ts-streaming.mjs
Tests include:
- Format detection
- HLS playlist generation
- Segment serving
- Direct streaming
- External streaming
- Conversion status
- Media access information
Manual Testing
-
Browser HLS Test:
// In browser console with hls.js loaded const hls = new Hls(); hls.loadSource('/api/stream/hls/109/playlist.m3u8'); hls.attachMedia(video); -
VLC Direct Test:
vlc http://localhost:3000/api/external-stream/109 -
Container Conversion Test:
curl -X POST http://localhost:3000/api/videos/109/convert-ts
Performance Comparison
| Method | Conversion Time | Browser Support | Quality | Seeking |
|---|---|---|---|---|
| HLS Streaming | 0s (instant) | ✅ (with hls.js) | Original | ✅ |
| Container Conversion | ~5-10s | ✅ (native) | Original | ✅ |
| Direct Streaming | 0s (instant) | ❌ (browsers) | Original | ✅ (VLC) |
Troubleshooting
Common Issues
-
"Video cannot be played"
- Check if hls.js is loaded
- Verify M3U8 playlist is valid
- Test segment URLs directly
-
"Seeking not working"
- Ensure Accept-Ranges header is set
- Check if duration metadata is available
- Verify keyframe intervals in source
-
"Slow loading"
- Check if faststart flag is used for MP4
- Verify server supports range requests
- Monitor network requests in dev tools
Debug Commands
# Check .ts file codec information
ffprobe -v quiet -print_format json -show_streams input.ts
# Verify HLS playlist
curl http://localhost:3000/api/stream/hls/109/playlist.m3u8
# Test segment serving
curl -I http://localhost:3000/api/stream/hls/109/segment/0.ts
Recommendations
For Downloaded .ts Files
- Primary: Use HLS streaming (current implementation)
- Fallback: Container conversion to .mp4
- External: Direct streaming for VLC/MPV
For Production
- Batch convert popular .ts files to .mp4 during off-peak hours
- Serve via CDN for better performance
- Monitor conversion success rates and user preferences
- Cache M3U8 playlists for better response times
Browser Integration
// Recommended ArtPlayer setup for .ts files
if (format.type === 'hls') {
if (Hls.isSupported()) {
const hls = new Hls({
enableWorker: false,
lowLatencyMode: false,
backBufferLength: 90
});
hls.loadSource(format.url);
hls.attachMedia(art.video);
}
}
Conclusion
Your observation about VLC's instant "conversion" is spot-on - it's container remuxing, not re-encoding. The .ts files you have likely contain web-compatible H.264/AAC streams that just need the right serving strategy.
The optimal approach is:
- HLS streaming for immediate playback (already implemented)
- Container conversion for maximum compatibility (API available)
- Direct streaming for external players (already working)
This gives users the best of all worlds while leveraging the fact that .ts files from streaming sites are already optimized for web delivery.