A simple browser-based player for viewing vehicle camera streams using WebSocket MPEGTS streams.
- Display two independent video streams side by side
- Simple interface with minimal controls
- Fetch stream links from API with vehicle ID
- Manual refresh button to reload streams
- Error handling and status messages
npm install ws-mpegts-player
// Import the module
import { MpegtsPlayer, StreamService } from 'ws-mpegts-player';
// Create a stream service instance
const streamService = new StreamService();
// Fetch stream links for a vehicle
async function getStreams() {
try {
const streamLinks = await streamService.getStreamLinks('MH12SX6507');
console.log(streamLinks);
// { streamlink1: "ws://...", streamlink2: "ws://..." }
return streamLinks;
} catch (error) {
console.error('Error fetching streams:', error);
}
}
// Create a player when DOM is ready
document.addEventListener('DOMContentLoaded', async () => {
// Get a reference to your video element
const videoElement = document.getElementById('videoPlayer');
// Get stream URL
const streams = await getStreams();
// Create the player
const player = MpegtsPlayer.createPlayer({
videoElement: videoElement,
url: streams.streamlink1,
autoplay: true,
onError: (error) => console.error('Player error:', error),
onPlaying: () => console.log('Video is now playing')
});
// Cleanup when needed
function stopPlayer() {
MpegtsPlayer.destroyPlayer(player);
}
});
// Initialize with custom options (optional)
const streamService = new StreamService({
timeout: 5000 // Default: 10000ms
});
// Available methods
streamService.getStreamLinks(vehicleId); // Returns Promise<{streamlink1, streamlink2}>
streamService.checkStreamActive(streamUrl, timeout); // Returns Promise<boolean>
streamService.getBestStream(vehicleId); // Returns Promise<string> (best available stream)
// Create a player
const player = MpegtsPlayer.createPlayer({
videoElement: document.getElementById('video'), // Required
url: 'ws://stream-url', // Required
autoplay: true, // Optional, default: false
onError: (error) => {}, // Optional
onPlaying: () => {}, // Optional
onStatistics: (stats) => {}, // Optional
playerConfig: {} // Optional mpegts.js config overrides
});
// Check if browser supports required features
const features = MpegtsPlayer.getFeatureSupport();
console.log(features.mseLivePlayback); // true if browser supports MSE live playback
// Destroy player when done
MpegtsPlayer.destroyPlayer(player);
// Check if a stream is active
MpegtsPlayer.checkStreamActive('ws://stream-url', 3000)
.then(isActive => console.log('Stream active:', isActive));
See examples/simple-player.html
for a complete implementation example.
import React, { useEffect, useRef, useState } from 'react';
import { MpegtsPlayer, StreamService } from 'ws-mpegts-player';
function VideoPlayer() {
const videoRef = useRef(null);
const [player, setPlayer] = useState(null);
const [vehicleId, setVehicleId] = useState('MH12SX6507');
const [status, setStatus] = useState('');
useEffect(() => {
// Cleanup function for when component unmounts
return () => {
if (player) {
MpegtsPlayer.destroyPlayer(player);
}
};
}, []);
const loadStream = async () => {
try {
setStatus('Loading stream...');
// Clean up previous player if it exists
if (player) {
MpegtsPlayer.destroyPlayer(player);
}
// Create service and fetch stream URLs
const streamService = new StreamService();
const streams = await streamService.getStreamLinks(vehicleId);
// Create new player
const newPlayer = MpegtsPlayer.createPlayer({
videoElement: videoRef.current,
url: streams.streamlink1,
autoplay: true,
onError: (error) => setStatus(`Error: ${error.detail || 'Player error'}`),
onPlaying: () => setStatus('Stream playing')
});
setPlayer(newPlayer);
} catch (error) {
setStatus(`Error: ${error.message}`);
}
};
return (
<div>
<div>
<input
type="text"
value={vehicleId}
onChange={(e) => setVehicleId(e.target.value)}
placeholder="Vehicle ID"
/>
<button onClick={loadStream}>Load Stream</button>
</div>
<div className="video-container">
<video ref={videoRef} controls style={{ width: '100%', height: '300px' }}></video>
</div>
<div>{status}</div>
</div>
);
}
export default VideoPlayer;
// video-player.component.ts
import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { MpegtsPlayer, StreamService } from 'ws-mpegts-player';
@Component({
selector: 'app-video-player',
template: `
<div>
<div>
<input
type="text"
[(ngModel)]="vehicleId"
placeholder="Vehicle ID"
/>
<button (click)="loadStream()">Load Stream</button>
</div>
<div class="video-container">
<video #videoElement controls style="width: 100%; height: 300px;"></video>
</div>
<div>{{ status }}</div>
</div>
`,
styleUrls: ['./video-player.component.css']
})
export class VideoPlayerComponent implements OnInit, OnDestroy {
@ViewChild('videoElement', { static: true }) videoElementRef!: ElementRef;
vehicleId: string = 'MH12SX6507';
status: string = '';
private player: any = null;
private streamService: StreamService;
constructor() {
this.streamService = new StreamService();
}
ngOnInit(): void {
// Component initialization
}
ngOnDestroy(): void {
// Clean up on component destruction
if (this.player) {
MpegtsPlayer.destroyPlayer(this.player);
}
}
async loadStream(): Promise<void> {
try {
this.status = 'Loading stream...';
// Clean up previous player if it exists
if (this.player) {
MpegtsPlayer.destroyPlayer(this.player);
}
// Fetch stream URLs
const streams = await this.streamService.getStreamLinks(this.vehicleId);
// Create new player
this.player = MpegtsPlayer.createPlayer({
videoElement: this.videoElementRef.nativeElement,
url: streams.streamlink1,
autoplay: true,
onError: (error: any) => this.status = `Error: ${error.detail || 'Player error'}`,
onPlaying: () => this.status = 'Stream playing'
});
} catch (error: any) {
this.status = `Error: ${error.message}`;
}
}
}
Note: For Angular, you'll need to add FormsModule
to your module imports for the [(ngModel)]
binding to work.
The player uses:
- mpegts.js for decoding and playing MPEG-TS streams over WebSocket
- Axios for API calls
- Plain JavaScript for DOM manipulation and player management
Each video player is implemented independently to ensure one stream doesn't affect the other's performance.
The system connects to a private API endpoint to retrieve WebSocket stream URLs for vehicle cameras. This endpoint requires a valid vehicle ID and returns two WebSocket URLs for different camera views.
If streams don't play:
- Check console logs for detailed error messages
- Verify the vehicle ID is correct
- Ensure both stream URLs are valid WebSocket URLs (starting with "ws://")
- Try refreshing the streams
This player works best in modern browsers with WebSocket and Media Source Extensions support:
- Chrome
- Firefox
- Edge
- Safari (limited support)
[Add your license information here]